mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
508 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4924bd249a | ||
|
|
a5e000a14c | ||
|
|
53eaccc892 | ||
|
|
e95cd4dd3a | ||
|
|
48b0c4025b | ||
|
|
2171df515d | ||
|
|
83d7460a0b | ||
|
|
38ad11dbef | ||
|
|
eddd6cb8b1 | ||
|
|
abf28593b1 | ||
|
|
bc4aeff164 | ||
|
|
632041a44a | ||
|
|
f1cd83e924 | ||
|
|
50bf004427 | ||
|
|
85a6372c2e | ||
|
|
eb76ea2039 | ||
|
|
14edf325bc | ||
|
|
e11ed353b8 | ||
|
|
f8521fda99 | ||
|
|
fa47d0321b | ||
|
|
095d982b62 | ||
|
|
0060378321 | ||
|
|
8ea6415424 | ||
|
|
eb24239c51 | ||
|
|
ac1c658870 | ||
|
|
cf032ab955 | ||
|
|
2d04878506 | ||
|
|
748bb5b191 | ||
|
|
f3b89f1c51 | ||
|
|
b2d388a210 | ||
|
|
c883e2bf0b | ||
|
|
f8ca0a8e08 | ||
|
|
99b1fd2fe2 | ||
|
|
b0a46a541d | ||
|
|
3aabd85604 | ||
|
|
9acd8c981e | ||
|
|
9353c489aa | ||
|
|
bc95dc1a1d | ||
|
|
1ecd32e017 | ||
|
|
6ef823347b | ||
|
|
bd75c1ab83 | ||
|
|
b3b943d330 | ||
|
|
a5151686ec | ||
|
|
24c1dd97df | ||
|
|
6f171620dc | ||
|
|
7428a87d80 | ||
|
|
79084f26c6 | ||
|
|
d5cd4b4273 | ||
|
|
bafd74b225 | ||
|
|
8df8ce85f2 | ||
|
|
a5b9984d78 | ||
|
|
4dd68f2221 | ||
|
|
21c02acd8c | ||
|
|
c7b25c60af | ||
|
|
41865f3af7 | ||
|
|
8f092e293f | ||
|
|
c888dfc1d6 | ||
|
|
6ebe3eff58 | ||
|
|
2ca3f0a356 | ||
|
|
698a991262 | ||
|
|
352bb98bc6 | ||
|
|
8c34313720 | ||
|
|
ce805a7860 | ||
|
|
86b8900b3d | ||
|
|
eb1bcee301 | ||
|
|
fd3b4b6a66 | ||
|
|
b09de5f112 | ||
|
|
8d1c92c490 | ||
|
|
bd98e3befb | ||
|
|
1aa71811b0 | ||
|
|
4e1b1ac98e | ||
|
|
ccbaef8541 | ||
|
|
8a30115398 | ||
|
|
3a1d393a0f | ||
|
|
66844b1d4c | ||
|
|
722d7b77fb | ||
|
|
5a2575c9a0 | ||
|
|
daad012466 | ||
|
|
f2cc686189 | ||
|
|
175ccff7e9 | ||
|
|
4a1e6f1540 | ||
|
|
d285865de5 | ||
|
|
4bcc9f8aec | ||
|
|
c6b2320cbd | ||
|
|
87be5aa72e | ||
|
|
3f0f675fd5 | ||
|
|
7c56fb836b | ||
|
|
2891d7314b | ||
|
|
ed13bb34d8 | ||
|
|
b9097d9462 | ||
|
|
59fcfdae81 | ||
|
|
f85304471f | ||
|
|
3fc67a5694 | ||
|
|
2314900829 | ||
|
|
680b792b19 | ||
|
|
0d734b753f | ||
|
|
fae33ca0a1 | ||
|
|
dc7ff1136e | ||
|
|
67ab05da63 | ||
|
|
54ba3b6513 | ||
|
|
13739b18aa | ||
|
|
7a198e62f9 | ||
|
|
e37955448e | ||
|
|
2dc9db17ab | ||
|
|
a3eb6dd552 | ||
|
|
35b782a10f | ||
|
|
8c4dc6ed36 | ||
|
|
1532fdcc8e | ||
|
|
68d959cb7a | ||
|
|
c364117fc0 | ||
|
|
d376fcc227 | ||
|
|
93b297c2d5 | ||
|
|
d158db618d | ||
|
|
934b95cde8 | ||
|
|
3563399126 | ||
|
|
6364009e45 | ||
|
|
1739017303 | ||
|
|
27d416f38b | ||
|
|
f9dac1c226 | ||
|
|
d1334038df | ||
|
|
4ebc6ab6c9 | ||
|
|
76905b095b | ||
|
|
daf014df6a | ||
|
|
ff4dd03379 | ||
|
|
114e305e25 | ||
|
|
4e04d99780 | ||
|
|
a9a88c5b13 | ||
|
|
71d4d30f3a | ||
|
|
8cbfb96141 | ||
|
|
919100daad | ||
|
|
d2f4c1ddd9 | ||
|
|
cb89fb69c1 | ||
|
|
51727b815d | ||
|
|
8bfdeeebd0 | ||
|
|
b963b08469 | ||
|
|
177551e081 | ||
|
|
7ab5ec8b40 | ||
|
|
8fd9c64c0c | ||
|
|
a9af3b9380 | ||
|
|
fc21063652 | ||
|
|
19864225f6 | ||
|
|
3312e14422 | ||
|
|
425d477168 | ||
|
|
b351b6a20d | ||
|
|
4b75211ad0 | ||
|
|
88c76c4a6c | ||
|
|
cfbd859d9e | ||
|
|
5851abbce8 | ||
|
|
d35bed4348 | ||
|
|
4e77bb05b9 | ||
|
|
fdbc2ef0e2 | ||
|
|
237cb3ffa5 | ||
|
|
7ed1a79b5b | ||
|
|
e36672f54c | ||
|
|
eac360571e | ||
|
|
9f59729fb1 | ||
|
|
9f063cb4da | ||
|
|
f593453328 | ||
|
|
871bdf5a82 | ||
|
|
fbf40335aa | ||
|
|
0c8a11c607 | ||
|
|
c13ffbc9b2 | ||
|
|
31f9edefa5 | ||
|
|
fe0195ad10 | ||
|
|
e3e2fff6e5 | ||
|
|
3b67ff52d5 | ||
|
|
17789f03f9 | ||
|
|
6fb464f57d | ||
|
|
6c277da869 | ||
|
|
4d5af32ce7 | ||
|
|
16a84b8d3e | ||
|
|
eebb251d2f | ||
|
|
4255a2f9ba | ||
|
|
5fcfb141a6 | ||
|
|
304baca7c5 | ||
|
|
fb2de46d88 | ||
|
|
f551952bf6 | ||
|
|
ec8d74fabd | ||
|
|
f732ad9639 | ||
|
|
31bfd6a235 | ||
|
|
a44c81a6bb | ||
|
|
df56d421f8 | ||
|
|
f5fad8d5e0 | ||
|
|
f92c64c4d3 | ||
|
|
2ca15d8b53 | ||
|
|
bc18db2bc2 | ||
|
|
a006074459 | ||
|
|
141eac9bc3 | ||
|
|
69dd1d167b | ||
|
|
f6aba4a5a4 | ||
|
|
f0b5f2737f | ||
|
|
5c177d671c | ||
|
|
1d112a21cc | ||
|
|
13bbf08e6c | ||
|
|
7c180113cd | ||
|
|
2ba4641796 | ||
|
|
d11de2cbac | ||
|
|
1725e45793 | ||
|
|
035df461e1 | ||
|
|
f6f5380df4 | ||
|
|
d8df5ceab5 | ||
|
|
dfe744ef13 | ||
|
|
2fbdf46fd6 | ||
|
|
2c100dd121 | ||
|
|
42cb14b9d9 | ||
|
|
c5cded87b1 | ||
|
|
b2ee4e1df0 | ||
|
|
db73166da7 | ||
|
|
8d21574a93 | ||
|
|
35bd5ccc55 | ||
|
|
6dd1410faf | ||
|
|
0cbf42e4e6 | ||
|
|
f0657ee5a8 | ||
|
|
29ee3a5f3a | ||
|
|
8cfaced4b4 | ||
|
|
61673222db | ||
|
|
f59f0cbb7f | ||
|
|
20af28597d | ||
|
|
942d83f54d | ||
|
|
0c6f132520 | ||
|
|
6319508937 | ||
|
|
ae6525e986 | ||
|
|
51d1690edc | ||
|
|
14d00f9228 | ||
|
|
5ad9f4107c | ||
|
|
6afa4ed327 | ||
|
|
bc140ec081 | ||
|
|
d904289060 | ||
|
|
e13bd4f323 | ||
|
|
5752f1b84a | ||
|
|
5e516ed6d1 | ||
|
|
2ceeeb82af | ||
|
|
2883e44a9d | ||
|
|
20747db2cc | ||
|
|
c2f22ac399 | ||
|
|
b8beede921 | ||
|
|
cd32158a73 | ||
|
|
a8ec6dbe37 | ||
|
|
f22af7c5fc | ||
|
|
a4b53f88a1 | ||
|
|
4567e2f4a4 | ||
|
|
8a3fd87784 | ||
|
|
c428ce32b2 | ||
|
|
2ae9c50d47 | ||
|
|
dfcc8d513d | ||
|
|
7c9d032c99 | ||
|
|
f6fc91a051 | ||
|
|
8b76daa35f | ||
|
|
8b883f556f | ||
|
|
beefaae0fa | ||
|
|
13e778b123 | ||
|
|
7f7c13a72a | ||
|
|
f2312e63eb | ||
|
|
d6adaa87c7 | ||
|
|
20e35a00ba | ||
|
|
8610ee8956 | ||
|
|
92fbdabbe5 | ||
|
|
25659ba920 | ||
|
|
b2ce60b843 | ||
|
|
c87ad08371 | ||
|
|
94688fddd4 | ||
|
|
e29eba9943 | ||
|
|
920dce96fe | ||
|
|
e2747525a6 | ||
|
|
a5989486ae | ||
|
|
9c58273832 | ||
|
|
9a9fa0c182 | ||
|
|
319d0b9866 | ||
|
|
5dbccaadf6 | ||
|
|
28a6777d83 | ||
|
|
21afa4ba97 | ||
|
|
d60dfa7ff3 | ||
|
|
5d3b2ec56f | ||
|
|
2c55a9caab | ||
|
|
6daedf198f | ||
|
|
8d52ce2ac9 | ||
|
|
63e484cc91 | ||
|
|
e3ecace5db | ||
|
|
f9add0b997 | ||
|
|
d3c942d475 | ||
|
|
3d1e28fb3a | ||
|
|
c07fa3a0bc | ||
|
|
ef94b311fa | ||
|
|
79d5b795e3 | ||
|
|
d0c20be7f3 | ||
|
|
6833275960 | ||
|
|
601a1ad2d1 | ||
|
|
db036f4dfc | ||
|
|
7bcd29abec | ||
|
|
c5b36af672 | ||
|
|
9da8544408 | ||
|
|
ab9a9ddab3 | ||
|
|
ceb695af01 | ||
|
|
1ffddf823f | ||
|
|
499134bc2d | ||
|
|
7a9763c6c7 | ||
|
|
db7bc75739 | ||
|
|
bd1dcd2a7f | ||
|
|
bc205cfe00 | ||
|
|
0f3dcf47ea | ||
|
|
3f165571d2 | ||
|
|
b2450b1924 | ||
|
|
061703db7b | ||
|
|
50f4327306 | ||
|
|
90206eac92 | ||
|
|
f1a5d6f870 | ||
|
|
ca506672a8 | ||
|
|
3041713eb3 | ||
|
|
dbc645e7b0 | ||
|
|
5d205800aa | ||
|
|
e5d11c81f3 | ||
|
|
d86c520509 | ||
|
|
854b421235 | ||
|
|
8206a5f3f4 | ||
|
|
0568475d59 | ||
|
|
b5a43031f9 | ||
|
|
ba41ba57f6 | ||
|
|
d84136dc92 | ||
|
|
ad78373b43 | ||
|
|
8980207fd6 | ||
|
|
33d8ee70d9 | ||
|
|
b86cd1bc3c | ||
|
|
57c22b484d | ||
|
|
834bd57ea6 | ||
|
|
7e26b7b902 | ||
|
|
4eb2e770c8 | ||
|
|
0208f6240c | ||
|
|
db88bfff8d | ||
|
|
a78b88cb90 | ||
|
|
a42dd9db83 | ||
|
|
a7d7cf1c2e | ||
|
|
1ec8bb5c8b | ||
|
|
d8e672f796 | ||
|
|
b577397d22 | ||
|
|
832afa6c5a | ||
|
|
b667d25f2a | ||
|
|
e237b5541b | ||
|
|
bf62106953 | ||
|
|
09b181449f | ||
|
|
c073bc49c1 | ||
|
|
7b2a2031a2 | ||
|
|
a90a2dadd4 | ||
|
|
c21aa98034 | ||
|
|
c967e1500c | ||
|
|
99212cc139 | ||
|
|
caab348a39 | ||
|
|
f799374183 | ||
|
|
1f8a129137 | ||
|
|
ba11725087 | ||
|
|
79f8503c09 | ||
|
|
5c7f285b9d | ||
|
|
b7415e1855 | ||
|
|
3def1f59e5 | ||
|
|
7b8a79b8ea | ||
|
|
9695438fcd | ||
|
|
49cd974dcb | ||
|
|
739d373204 | ||
|
|
896cb83eb2 | ||
|
|
22f1261efa | ||
|
|
4648b9c8eb | ||
|
|
e77770f608 | ||
|
|
bfa2ae8bc4 | ||
|
|
9c13d21f69 | ||
|
|
16ce501582 | ||
|
|
61617db239 | ||
|
|
ac74a9c80e | ||
|
|
c8812db585 | ||
|
|
95aaa8fc2e | ||
|
|
deb9dbed61 | ||
|
|
0feb8dc73c | ||
|
|
6bfbdbd9df | ||
|
|
2160b369bb | ||
|
|
de91defc20 | ||
|
|
3fbff95b2b | ||
|
|
6facababd7 | ||
|
|
dc3dc80d8f | ||
|
|
202fbf3dbc | ||
|
|
f6283f4807 | ||
|
|
1f7ddbecdf | ||
|
|
129af0ba9e | ||
|
|
eed267ed3f | ||
|
|
e195770181 | ||
|
|
cbddea701a | ||
|
|
3eefa3365f | ||
|
|
d22f9ddfe3 | ||
|
|
5c9416313a | ||
|
|
4b063aaf97 | ||
|
|
bbfd4967cf | ||
|
|
c5742350d1 | ||
|
|
753286cdf6 | ||
|
|
22028b37ed | ||
|
|
3483c736ba | ||
|
|
20989c31c8 | ||
|
|
cee797017b | ||
|
|
bceac916fe | ||
|
|
7d8a081e3f | ||
|
|
4bd36ece9a | ||
|
|
b95644d5e5 | ||
|
|
791cc17b27 | ||
|
|
40b1b67b29 | ||
|
|
b8cb4ad521 | ||
|
|
6b50ca034b | ||
|
|
43df9c3ff5 | ||
|
|
dff48692ca | ||
|
|
44a8085463 | ||
|
|
934eb8264e | ||
|
|
dc1bb6a55e | ||
|
|
fe9b5b51e8 | ||
|
|
f35aa046c1 | ||
|
|
a708fa5f6e | ||
|
|
bb78b1bf27 | ||
|
|
931fae62c6 | ||
|
|
c1e657a5e3 | ||
|
|
1e2d42ce23 | ||
|
|
5d367a5c27 | ||
|
|
1d03f7efbf | ||
|
|
5125fd4d6c | ||
|
|
d079035adf | ||
|
|
06bfcdacc2 | ||
|
|
ab844202bc | ||
|
|
f05ddf8fcd | ||
|
|
f36df3ea09 | ||
|
|
df28ebe573 | ||
|
|
3a44affc63 | ||
|
|
19be1db46c | ||
|
|
7101c3588a | ||
|
|
5573244583 | ||
|
|
ad1db34c86 | ||
|
|
379cc25099 | ||
|
|
df6a6ce066 | ||
|
|
27735ccc01 | ||
|
|
d614eb088e | ||
|
|
f1088e9471 | ||
|
|
f6b8cc71cc | ||
|
|
d35144e0e9 | ||
|
|
f7fe1e066c | ||
|
|
18366dd294 | ||
|
|
106d717157 | ||
|
|
296775d231 | ||
|
|
114d8d7dfc | ||
|
|
2392f57d62 | ||
|
|
a0b199d208 | ||
|
|
6c4584a00a | ||
|
|
5d565c55a7 | ||
|
|
fbc902d16e | ||
|
|
051a65f0bb | ||
|
|
ffc311e0e9 | ||
|
|
d738eee5d9 | ||
|
|
58a00106d3 | ||
|
|
d0617714ca | ||
|
|
6ae3316cd1 | ||
|
|
c1577905cd | ||
|
|
d12f6a1191 | ||
|
|
0f5612fdd4 | ||
|
|
a77fa83c80 | ||
|
|
75bc2b7b35 | ||
|
|
ac6284819a | ||
|
|
2e09e5fdfa | ||
|
|
5c09130782 | ||
|
|
677b064e97 | ||
|
|
a30512f4e4 | ||
|
|
e20229208f | ||
|
|
f67bb81de2 | ||
|
|
f98cdfeb0f | ||
|
|
ba264c1557 | ||
|
|
11a08298ff | ||
|
|
72ac2f628b | ||
|
|
dd87bf77f8 | ||
|
|
d730ca2c25 | ||
|
|
0d09baee3c | ||
|
|
7ea26b68e7 | ||
|
|
e7334a6c4f | ||
|
|
404dc772d4 | ||
|
|
7754123e30 | ||
|
|
16b950d5a0 | ||
|
|
0ba3fee968 | ||
|
|
a2113fcdcc | ||
|
|
ec7fbeeb22 | ||
|
|
5f969bf4aa | ||
|
|
8a197aea45 | ||
|
|
c6bc10f1ba | ||
|
|
5830dfa991 | ||
|
|
fc44edb0fc | ||
|
|
cb02c0328c | ||
|
|
71d79ff45b | ||
|
|
c4e2730ced | ||
|
|
65fdd7c5b4 | ||
|
|
42fee3bd3e | ||
|
|
b4d45af268 | ||
|
|
7125f2fa5e | ||
|
|
4993ed00a2 | ||
|
|
a2b622a343 | ||
|
|
c401035209 | ||
|
|
4324afc593 | ||
|
|
de5b99dbb9 | ||
|
|
374999df1f | ||
|
|
ba7455c99e | ||
|
|
ad592cdc59 | ||
|
|
78b2dac71c | ||
|
|
5d5f224f66 | ||
|
|
c70762fbee | ||
|
|
166bbbbc72 | ||
|
|
8bdcaa047a | ||
|
|
ee557cc552 | ||
|
|
d7b99be51f | ||
|
|
ed85d508ed | ||
|
|
ffa8b053d7 | ||
|
|
c39ddbc7a7 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,3 +8,5 @@ examples
|
|||||||
*.bin
|
*.bin
|
||||||
*.ans
|
*.ans
|
||||||
*.patch
|
*.patch
|
||||||
|
*.zip
|
||||||
|
result
|
||||||
@@ -10,20 +10,20 @@ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
|||||||
set(CURSES_NEED_NCURSES TRUE)
|
set(CURSES_NEED_NCURSES TRUE)
|
||||||
set(CURSES_NEED_WIDE TRUE)
|
set(CURSES_NEED_WIDE TRUE)
|
||||||
|
|
||||||
#use cmake option -DAERO=ON to enable Aero Builds (OSS support and specific tweaks)
|
#use cmake option -DCOLORS=OFF to disable color output (ncurses)
|
||||||
option(AERO
|
|
||||||
"Build for Aero Environments (Cygwin)" OFF)
|
|
||||||
if (AERO)
|
|
||||||
add_definitions(-DAERO_BUILD)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
#use cmake option -DCOLORS=OFF to disable color output
|
|
||||||
option(COLORS
|
option(COLORS
|
||||||
"Build with Colors Enabled" ON)
|
"Build with Colors Enabled" ON)
|
||||||
if (COLORS)
|
if (COLORS)
|
||||||
add_definitions(-DPRETTY_COLORS)
|
add_definitions(-DPRETTY_COLORS)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
#use cmake option -DCOLORSLOGS=OFF to disable color output (terminal/logs)
|
||||||
|
option(COLORSLOGS
|
||||||
|
"Build with Colors Enabled" ON)
|
||||||
|
if (COLORSLOGS)
|
||||||
|
add_definitions(-DPRETTY_COLORS_LOGS)
|
||||||
|
endif ()
|
||||||
|
|
||||||
#use cmake option -DPVC=ON to enable Provoice Conventional Frame Sync
|
#use cmake option -DPVC=ON to enable Provoice Conventional Frame Sync
|
||||||
option(PVC
|
option(PVC
|
||||||
"Build with Provoice Conventional Frame Sync Enabled" OFF)
|
"Build with Provoice Conventional Frame Sync Enabled" OFF)
|
||||||
@@ -52,14 +52,13 @@ git_describe(GIT_TAG)
|
|||||||
|
|
||||||
find_package(LibSndFile REQUIRED)
|
find_package(LibSndFile REQUIRED)
|
||||||
find_package(MBE REQUIRED)
|
find_package(MBE REQUIRED)
|
||||||
find_package(ITPP REQUIRED)
|
|
||||||
find_package(RTLSDR)
|
find_package(RTLSDR)
|
||||||
find_package(Curses REQUIRED)
|
find_package(Curses REQUIRED)
|
||||||
find_package(PulseAudio REQUIRED)
|
find_package(PulseAudio REQUIRED)
|
||||||
find_package(CODEC2)
|
find_package(CODEC2)
|
||||||
|
|
||||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
|
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIRS})
|
||||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
|
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARIES})
|
||||||
|
|
||||||
if(RTLSDR_FOUND)
|
if(RTLSDR_FOUND)
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
@@ -90,7 +89,9 @@ ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
|||||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||||
|
|
||||||
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
|
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
|
||||||
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>)
|
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>
|
||||||
|
-Wmisleading-indentation -Wparentheses -Wunused-value -Wreturn-type
|
||||||
|
-Wtautological-compare)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
|
||||||
# Digital Speech Decoder - Florida Man Edition
|
# Digital Speech Decoder - Florida Man Edition
|
||||||
|
|
||||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and [Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
|
||||||
|
|
||||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, ilyacodes, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
# - Try to find ITPP
|
|
||||||
# Once done this will define
|
|
||||||
#
|
|
||||||
# ITPP_FOUND - System has ITPP
|
|
||||||
# ITPP_INCLUDE_DIR - The ITPP include directory
|
|
||||||
# ITPP_LIBRARY - The library needed to use ITPP
|
|
||||||
#
|
|
||||||
|
|
||||||
find_path(ITPP_INCLUDE_DIR itpp/itcomm.h)
|
|
||||||
|
|
||||||
set(ITPP_NAMES ${ITPP_NAMES} itpp libitpp libitpp.dll)
|
|
||||||
FIND_LIBRARY(ITPP_LIBRARY NAMES ${ITPP_NAMES})
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(ITPP DEFAULT_MSG ITPP_LIBRARY ITPP_INCLUDE_DIR)
|
|
||||||
244
cyg_portable.sh
Normal file
244
cyg_portable.sh
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
#
|
||||||
|
cdir=$(pwd)
|
||||||
|
clear
|
||||||
|
printf "DSD-FME Digital Speech Decoder - Florida Man Edition Portable Cygwin Creator\n"
|
||||||
|
printf "Only use this in a Cygwin64 Environment. Will not work in a Linux Environment!\n"
|
||||||
|
read -p "Do you want to make a portable copy? y/N " RELEASE
|
||||||
|
RELEASE=$(printf "$RELEASE"|tr '[:upper:]' '[:lower:]')
|
||||||
|
if [ "$RELEASE" = "y" ]; then
|
||||||
|
|
||||||
|
printf "Copying files to dsd-fme-portable folder and making zip file. Please wait!\n"
|
||||||
|
cd ~
|
||||||
|
|
||||||
|
#create a dsd-fme-portable folder and copy all the needed items for a portable release version
|
||||||
|
mkdir dsd-fme-portable
|
||||||
|
cd dsd-fme-portable
|
||||||
|
#all of these folders may not be necessary
|
||||||
|
mkdir sourcecode
|
||||||
|
mkdir bin
|
||||||
|
mkdir dev
|
||||||
|
cd dev
|
||||||
|
mkdir shm
|
||||||
|
cd ..
|
||||||
|
mkdir dsd-fme
|
||||||
|
mkdir logs
|
||||||
|
mkdir WAV
|
||||||
|
mkdir etc
|
||||||
|
mkdir home
|
||||||
|
mkdir lib
|
||||||
|
mkdir tmp
|
||||||
|
mkdir usr
|
||||||
|
cd usr
|
||||||
|
mkdir share
|
||||||
|
cd share
|
||||||
|
mkdir terminfo
|
||||||
|
cd ~
|
||||||
|
|
||||||
|
#start copying things
|
||||||
|
|
||||||
|
#terminfo is needed for ncurses
|
||||||
|
cp -r /usr/share/terminfo/* dsd-fme-portable/usr/share/terminfo
|
||||||
|
|
||||||
|
#copy required items from the root bin folder to release bin folder
|
||||||
|
cp /bin/ls.exe dsd-fme-portable/bin/
|
||||||
|
cp /bin/bash.exe dsd-fme-portable/bin/
|
||||||
|
cp /bin/ncurses6-config dsd-fme-portable/bin/
|
||||||
|
cp /bin/ncursesw6-config dsd-fme-portable/bin/
|
||||||
|
cp /bin/pacat.exe dsd-fme-portable/bin/
|
||||||
|
cp /bin/pactl.exe dsd-fme-portable/bin/
|
||||||
|
cp /bin/padsp dsd-fme-portable/bin/
|
||||||
|
cp /bin/pamon dsd-fme-portable/bin/
|
||||||
|
cp /bin/paplay dsd-fme-portable/bin/
|
||||||
|
cp /bin/parec dsd-fme-portable/bin/
|
||||||
|
cp /bin/parecord dsd-fme-portable/bin/
|
||||||
|
cp /bin/pulseaudio.exe dsd-fme-portable/bin/
|
||||||
|
cp /bin/tty.exe dsd-fme-portable/bin/
|
||||||
|
|
||||||
|
#start copying things from the etc folder
|
||||||
|
cp -r /etc/pulse/ dsd-fme-portable/etc/
|
||||||
|
|
||||||
|
#start copying things to the lib folder
|
||||||
|
cp -r /lib/pulseaudio/ dsd-fme-portable/lib/
|
||||||
|
|
||||||
|
#start copying things into the dsd-fme folder
|
||||||
|
cp dsd-fme/build/dsd-fme.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp -r dsd-fme/examples dsd-fme-portable/dsd-fme/
|
||||||
|
cp .bash_profile dsd-fme-portable/dsd-fme/
|
||||||
|
cp .bashrc dsd-fme-portable/dsd-fme/
|
||||||
|
cp .inputrc dsd-fme-portable/dsd-fme/
|
||||||
|
cp .profile dsd-fme-portable/dsd-fme/
|
||||||
|
|
||||||
|
#move (cut) the bat files to the portable folder root and delete the other ones so users won't get confused
|
||||||
|
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/*.bat dsd-fme-portable/
|
||||||
|
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/example_options.txt dsd-fme-portable/
|
||||||
|
mv dsd-fme-portable/dsd-fme/examples/cygwin_bat/complete_usage_options.txt dsd-fme-portable/
|
||||||
|
rm -rf dsd-fme-portable/dsd-fme/examples/cygwin_bat
|
||||||
|
|
||||||
|
#change .bat files permissions to be read/write/executable by all users (for some reason, this is not preserved)
|
||||||
|
chmod 777 dsd-fme-portable/*.bat
|
||||||
|
|
||||||
|
#copy the license, copyright, source code, and things that should be included in all portable releases
|
||||||
|
cp dsd-fme/COPYRIGHT dsd-fme-portable/sourcecode/
|
||||||
|
cp dsd-fme/DSD_Author.pgp dsd-fme-portable/sourcecode/
|
||||||
|
cp dsd-fme/dsd-fme-qgis-map.qgz dsd-fme-portable/sourcecode/
|
||||||
|
cp dsd-fme/README.md dsd-fme-portable/sourcecode/
|
||||||
|
cp dsd-fme/dsd-fme2.png dsd-fme-portable/sourcecode/
|
||||||
|
cp dsd-fme/dsd-fme3.png dsd-fme-portable/sourcecode/
|
||||||
|
|
||||||
|
cp dsd-fme/CMakeLists.txt dsd-fme-portable/sourcecode/
|
||||||
|
cp -r dsd-fme/src dsd-fme-portable/sourcecode/
|
||||||
|
cp -r dsd-fme/include dsd-fme-portable/sourcecode/
|
||||||
|
cp -r dsd-fme/cmake dsd-fme-portable/sourcecode/
|
||||||
|
cp -r dsd-fme/patch dsd-fme-portable/sourcecode/
|
||||||
|
|
||||||
|
#compiled items into release dsd-fme folder
|
||||||
|
cp codec2/build/src/cygcodec2* dsd-fme-portable/dsd-fme/
|
||||||
|
cp rtl-sdr/build/src/cyg* dsd-fme-portable/dsd-fme/
|
||||||
|
cp mbelib/build/cygmbe* dsd-fme-portable/dsd-fme/
|
||||||
|
|
||||||
|
#bin items into release dsd-fme folder (uisng * where version numbering may exist, those may be upgraded if hard coded)
|
||||||
|
cp /bin/bash.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cut.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygao* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygarchive* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygargp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygassuan* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygasyncns* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygatomic* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygattr* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygavahi-client* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygavahi-common* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygavahi-wrap* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygblkid* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygbrotlicommon* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygbrotlidec* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygbz2* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcares* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcheck.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcli.dll dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcom_err* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcrypt* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcrypto* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygcurl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygdb_cxx* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygdb_sql* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygdb* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygdbus* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygedit* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygexpat* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfdisk* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygffi* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3_threads* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3f_threads* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3f* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3l_threads* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfftw3l* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygfido2* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygFLAC* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygformw* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggc* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggdbm_compat* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggdbm*.dll dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggio* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygglib* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggmodule* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggmp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggnutls* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggobject* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggomp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggpg-error* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggpgme* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggsm* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggssapi_krb5* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyggthread* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygguile* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyghistory* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyghogweed* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygICE* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygiconv* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygid3tag* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygidn* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygintl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygisl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygjsoncpp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygk5crypto* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygkrb5* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyglber* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygldap* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygltdl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyglz* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygma* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygmenuw* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygmeta* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygmp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygncurses* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygnettle* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygnghttp* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygobjc* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygogg* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygopus* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygorc* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygp11* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpanel* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpath.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpcre* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygperl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpipe* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpkg* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpng* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpopt* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygprotocol* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpsl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygpulse* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygquadmath* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygreadline* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygrhash* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygrunsrv.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsamplerate* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsasl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygserver* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygSM* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsmart* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsndfile* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsox* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygspeex* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygsqlite* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygssh* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygssl* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygstart.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygstdc* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygtasn* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygtdb* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygticw* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygtwo* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygunistring* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygusb* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyguuid* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cyguv* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygvorbis* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygwavpack* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygwin1.dll dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygwrap* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygX* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygx* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/cygz* dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/grep.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/ls.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/mintty.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/pacat.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/pacmd.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/pactl.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/padsp dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/pamon dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/paplay dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/parec dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/pulseaudio.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/tail.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/touch.exe dsd-fme-portable/dsd-fme/
|
||||||
|
cp /bin/tty.exe dsd-fme-portable/dsd-fme/
|
||||||
|
|
||||||
|
zip -r dsd-fme-x86-64-cygwin-portable.zip dsd-fme-portable
|
||||||
|
|
||||||
|
fi
|
||||||
14
cyg_rebuild.sh
Normal file
14
cyg_rebuild.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
#
|
||||||
|
clear
|
||||||
|
printf "DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||||
|
Automatic Git Pull and Rebuild for Cygwin\n\n"
|
||||||
|
sleep 1
|
||||||
|
##Open your clone folder##
|
||||||
|
git pull
|
||||||
|
sleep 2
|
||||||
|
##cd into your build folder##
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
make install
|
||||||
@@ -17,11 +17,6 @@ if [ "$ANSWER" = "y" ]; then
|
|||||||
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
||||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
||||||
|
|
||||||
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
|
|
||||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
|
|
||||||
git clone https://github.com/lwvmobile/mbelib
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
cd mbelib
|
cd mbelib
|
||||||
git checkout ambe_tones
|
git checkout ambe_tones
|
||||||
|
|||||||
77
download-and-install-cygwin.sh
Normal file
77
download-and-install-cygwin.sh
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
#
|
||||||
|
cdir=$(pwd)
|
||||||
|
clear
|
||||||
|
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer For Cygwin\n
|
||||||
|
This will install the required packages, clone, build, and install DSD-FME only.
|
||||||
|
This has been tested on Cygwin x86-64 as of 20250211. This may take a while!\n
|
||||||
|
MBELib is considered a requirement on this build.
|
||||||
|
You must view the Patent Notice prior to continuing.
|
||||||
|
The Patent Notice can be found at the site below.
|
||||||
|
https://github.com/lwvmobile/mbelib#readme
|
||||||
|
Please confirm that you have viewed the patent notice by entering y below.\n\n"
|
||||||
|
read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||||
|
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||||
|
if [ "$ANSWER" = "y" ]; then
|
||||||
|
|
||||||
|
#is this needed?
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
echo $LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
#MBELIB
|
||||||
|
cd $cdir
|
||||||
|
printf "Installing mbelib\n Please wait!\n"
|
||||||
|
git clone https://github.com/lwvmobile/mbelib.git
|
||||||
|
cd mbelib
|
||||||
|
git checkout ambe_tones
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
make install
|
||||||
|
cp cygmbe-1.dll /bin
|
||||||
|
|
||||||
|
#CODEC2
|
||||||
|
cd $cdir
|
||||||
|
printf "Installing codec2\n Please wait!\n"
|
||||||
|
git clone https://github.com/drowe67/codec2.git
|
||||||
|
cd codec2
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
make install
|
||||||
|
|
||||||
|
#RTL-SDR
|
||||||
|
cd $cdir
|
||||||
|
printf "Installing RTL-SDR\n Please wait!\n"
|
||||||
|
git clone https://github.com/lwvmobile/rtl-sdr.git
|
||||||
|
cd rtl-sdr
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
make install
|
||||||
|
|
||||||
|
#DSD-FME
|
||||||
|
cd $cdir
|
||||||
|
printf "Installing DSD-FME\n Please wait!\n"
|
||||||
|
git clone https://github.com/lwvmobile/dsd-fme.git
|
||||||
|
cd dsd-fme
|
||||||
|
#git checkout aw_dev
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCOLORSLOGS=OFF ..
|
||||||
|
make -j $(nproc)
|
||||||
|
make install
|
||||||
|
cd $cdir
|
||||||
|
|
||||||
|
#call the cyg_portable script
|
||||||
|
sh dsd-fme/cyg_portable.sh
|
||||||
|
|
||||||
|
printf "Any issues, Please report to either:\nhttps://github.com/lwvmobile/dsd-fme/issues or\nhttps://forums.radioreference.com/threads/dsd-fme.438137/\n\n"
|
||||||
|
|
||||||
|
else
|
||||||
|
printf "Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.\n\n"
|
||||||
|
fi
|
||||||
38
download-and-install-ubuntu2404lts.sh
Normal file
38
download-and-install-ubuntu2404lts.sh
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
#
|
||||||
|
cdir=$(pwd)
|
||||||
|
clear
|
||||||
|
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer\n
|
||||||
|
MBELib is considered a requirement on this build.
|
||||||
|
You must view the Patent Notice prior to continuing.
|
||||||
|
The Patent Notice can be found at the site below.
|
||||||
|
https://github.com/lwvmobile/mbelib#readme
|
||||||
|
Please confirm that you have viewed the patent notice by entering y below:\n\n"
|
||||||
|
read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||||
|
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||||
|
if [ "$ANSWER" = "y" ]; then
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
|
||||||
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
|
cd mbelib
|
||||||
|
git checkout ambe_tones
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
cd $cdir
|
||||||
|
git clone https://github.com/lwvmobile/dsd-fme
|
||||||
|
cd dsd-fme
|
||||||
|
#git checkout audio_work
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make -j $(nproc)
|
||||||
|
sudo make install
|
||||||
|
sudo ldconfig
|
||||||
|
else
|
||||||
|
printf "\nSorry, you cannot build DSD-FME without acknowledging the Patent Notice.\nExiting...\n\n"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
@@ -12,13 +12,7 @@ read -p "Have you viewed the patent notice? y/N " ANSWER
|
|||||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||||
if [ "$ANSWER" = "y" ]; then
|
if [ "$ANSWER" = "y" ]; then
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev libcodec2-dev
|
||||||
chkitpp=$(sudo apt list libitpp-dev 2>&1|grep -ci "installed")
|
|
||||||
if [ "$chkitpp" -lt "1" ];then
|
|
||||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
|
||||||
read -p "Press Enter to exit..." x
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
git clone https://github.com/lwvmobile/mbelib
|
git clone https://github.com/lwvmobile/mbelib
|
||||||
cd mbelib
|
cd mbelib
|
||||||
git checkout ambe_tones
|
git checkout ambe_tones
|
||||||
|
|||||||
BIN
dsd-fme2.png
BIN
dsd-fme2.png
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 725 KiB |
BIN
dsd-fme3.png
BIN
dsd-fme3.png
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 109 KiB |
74
examples/Audio_Plumbing.md
Normal file
74
examples/Audio_Plumbing.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## Audio Plumbing
|
||||||
|
|
||||||
|
While using DSD-FME to demodulate and decode RF Audio, you will find it necessary to properly plumb (or route) audio from each input source and output sink properly. This mini tutorial aims to help you do such when using Pulse Audio.
|
||||||
|
|
||||||
|
You will first want to locate and run the virtualsink.sh script file via `sh virtualsink.sh` command. This will create two null-sink, or 'virtual sinks' for us to plumb audio from point A to point B.
|
||||||
|
|
||||||
|
Here are screenshots of a proper setup using pavucontrol, or "Pulse Audio Volume Control", having voice input from the encoder listening to your microphone, the RF Output going into the "Virtual_Sink" null-sink, and on the playback side, playing back voice to our speakers, with RF modulated audio being monitored on "Virtual-Sink" null-sink.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The general idea is that we want to route RF modulated audio into our Virtual_Sink and have our decoder listen to the same sink. Voice Output should always be to Audio Hardware (speakers, headphones, etc).
|
||||||
|
|
||||||
|
Note, that using the virtualsink.sh will create these sinks for us for the duration of your computers boot. If you reboot, they will not persist. Configuration files can be modified to always have these sinks available, or the `virtualsink.sh` script can be executed on login, but you must do so at your own risk and own research, it is out of the scope of this tutorial to create persistent sinks.
|
||||||
|
|
||||||
|
In case of the usage of a headless environment and pavucontrol is not viable, you may use alternatives such as pulsemixer which is similar in functionality, just as a CLI tool and not a GUI tool.
|
||||||
|
|
||||||
|
Users can now use the `-O` CLI argument to list out all pulse audio input sources and output sinks and pass an optional argument alongside `pulse`, appending the name or index number to select the device each time. This method will work in both Linux environments as well as Cygwin builds (making sure to start the pulseaudio.exe server in the back first with the specified .bat file or command, see below).
|
||||||
|
|
||||||
|
For Example:
|
||||||
|
|
||||||
|
The Output (truncated) of `dsd-fme -O`
|
||||||
|
|
||||||
|
```
|
||||||
|
=======[ Output Device #1 ]=======
|
||||||
|
Description: Family 17h (Models 00h-0fh) HD Audio Controller Analog Stereo
|
||||||
|
Name: alsa_output.pci-0000_0d_00.3.analog-stereo
|
||||||
|
Index: 1
|
||||||
|
|
||||||
|
=======[ Output Device #4 ]=======
|
||||||
|
Description: Virtual_Sink1
|
||||||
|
Name: virtual_sink1
|
||||||
|
Index: 4
|
||||||
|
|
||||||
|
=======[ Output Device #5 ]=======
|
||||||
|
Description: Virtual_Sink2
|
||||||
|
Name: virtual_sink2
|
||||||
|
Index: 5
|
||||||
|
|
||||||
|
=======[ Input Device #2 ]=======
|
||||||
|
Description: Family 17h (Models 00h-0fh) HD Audio Controller Analog Stereo
|
||||||
|
Name: alsa_input.pci-0000_0d_00.3.analog-stereo
|
||||||
|
Index: 2
|
||||||
|
|
||||||
|
=======[ Input Device #5 ]=======
|
||||||
|
Description: Monitor of Virtual_Sink1
|
||||||
|
Name: virtual_sink1.monitor
|
||||||
|
Index: 5
|
||||||
|
|
||||||
|
=======[ Input Device #6 ]=======
|
||||||
|
Description: Monitor of Virtual_Sink2
|
||||||
|
Name: virtual_sink2.monitor
|
||||||
|
Index: 6
|
||||||
|
```
|
||||||
|
|
||||||
|
You might use any of the following for input and output options:
|
||||||
|
|
||||||
|
```
|
||||||
|
-i pulse
|
||||||
|
-i pulse:6
|
||||||
|
-i pulse:virtual_sink2.monitor
|
||||||
|
|
||||||
|
-o pulse
|
||||||
|
-o pulse:1
|
||||||
|
-o pulse:alsa_output.pci-0000_0d_00.3.analog-stereo
|
||||||
|
```
|
||||||
|
|
||||||
|
Something to keep in mind is that often times, you only need to set these values once, as a pulse audio server (or plugin) can often times remember these settings, even across reboots, as long as the same hardware is present for future use (real or null-sink).
|
||||||
|
|
||||||
|
<!-- TODO: Add This later -->
|
||||||
|
<!-- Cygwin Note: Running the supplied `0p - start-pulse-audio-backend.bat` file will not only start up the pulse audio server for you, but also setup your null-sinks, and enumerate all devices for you to use, making it an easy selection for your start up .bat files. See any notes in the precomplied .zip file for more information. -->
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
### Example Usage and Notes!
|
### Example Usage and Notes!
|
||||||
|
|
||||||
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
|
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches.
|
||||||
|
|
||||||
```
|
```
|
||||||
-ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
|
-ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
|
||||||
@@ -8,7 +8,11 @@
|
|||||||
-fa Legacy Auto (not recommended)
|
-fa Legacy Auto (not recommended)
|
||||||
-fi NXDN48
|
-fi NXDN48
|
||||||
-fn NXDN96
|
-fn NXDN96
|
||||||
-fp EDACS/Provoice
|
-fp Provoice
|
||||||
|
-fh EDACS Standard / Network
|
||||||
|
-fH EDACS Standard / Network with ESK
|
||||||
|
-fe EDACS Extended Addresssing
|
||||||
|
-fE EDACS Extended Addressing with ESK
|
||||||
-fm dPMR, also may need to use -xd if inverted dPMR.
|
-fm dPMR, also may need to use -xd if inverted dPMR.
|
||||||
-f1 P25P1
|
-f1 P25P1
|
||||||
-f2 P25P2 (may need to specify wacn/sys/nac manually if traffic channel)
|
-f2 P25P2 (may need to specify wacn/sys/nac manually if traffic channel)
|
||||||
@@ -45,7 +49,9 @@ and in a second terminal tab, same folder, run
|
|||||||
|
|
||||||
`tail -n 40 -f voice.log`
|
`tail -n 40 -f voice.log`
|
||||||
|
|
||||||
Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently)
|
### Audio Plumbing
|
||||||
|
|
||||||
|
Please see [Audio Plumbing](https://github.com/lwvmobile/dsd-fme/blob/aw_dev/examples/Audio_Plumbing.md "Audio Plumbing") for general help with audio plumbing (routing from A to B).
|
||||||
|
|
||||||
### Input ###
|
### Input ###
|
||||||
|
|
||||||
@@ -74,7 +80,7 @@ Detailed Setup:
|
|||||||
|
|
||||||
```
|
```
|
||||||
RTL-SDR options:
|
RTL-SDR options:
|
||||||
Usage: rtl:dev:freq:gain:ppm:bw:sq:udp
|
Usage: rtl:dev:freq:gain:ppm:bw:sq:vol
|
||||||
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
||||||
dev <num> RTL-SDR Device Index Number
|
dev <num> RTL-SDR Device Index Number
|
||||||
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||||
@@ -82,9 +88,9 @@ RTL-SDR options:
|
|||||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||||
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
||||||
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||||
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
|
vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)
|
||||||
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
|
Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T
|
||||||
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
|
Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -100,11 +106,11 @@ and in a second terminal tab, same folder, run
|
|||||||
|
|
||||||
EDACS Trunking (w/ channel map import)
|
EDACS Trunking (w/ channel map import)
|
||||||
|
|
||||||
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice, Analog Voice Monitoring and Per Call is Experimental)
|
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (see switches above for STD/NET, EA, and ESK modes)
|
||||||
|
|
||||||
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
`dsd-fme -i tcp -fE -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
||||||
|
|
||||||
--NXDN48 Trunking (standard band plan) with SDR++ (untested for frequency accuracy)
|
--NXDN48 Trunking (Direct Frequency Assignment) with SDR++ (untested for frequency accuracy)
|
||||||
|
|
||||||
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
|
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
|
||||||
|
|
||||||
@@ -165,7 +171,7 @@ Some Keyboard Shortcuts have been implemented for testing to see how users like
|
|||||||
esc or arrow keys - ncurses menu
|
esc or arrow keys - ncurses menu
|
||||||
q - quit
|
q - quit
|
||||||
c - toggle compact mode
|
c - toggle compact mode
|
||||||
h - toggle call history
|
h - cycle event history short, long, or off
|
||||||
z - toggle console payloads
|
z - toggle console payloads
|
||||||
a - toggle call alert beep
|
a - toggle call alert beep
|
||||||
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
|
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
|
||||||
@@ -176,9 +182,9 @@ M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
|
|||||||
R - start capturing symbol capture bin (date/time name file)
|
R - start capturing symbol capture bin (date/time name file)
|
||||||
r - stop capturing symbol capture bin
|
r - stop capturing symbol capture bin
|
||||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||||
s - stop playing symbol capture bin or wav input file
|
s - stop playing symbol capture bin or wav input file (lower s)
|
||||||
P - start per call decoded wav files (Capital P)
|
P - start per call decoded wav files (Capital P)
|
||||||
p - stop per call decoded wav files (Lower p)
|
p - stop per call decoded wav files (lower p)
|
||||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||||
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
|
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
|
||||||
@@ -196,8 +202,25 @@ Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
|||||||
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||||
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||||
|
|
||||||
k - Hold TG in Slot 1 or Conventional, or clear current hold (Testing/WIP: DMR T3 Only)
|
k - Hold TG in Slot 1 or Conventional, or clear current hold
|
||||||
l - Hold TG in Slot 2 on TDMA Systems, or clear current hold (Testing/WIP: DMR T3 Only)
|
l - Hold TG in Slot 2 on TDMA Systems, or clear current hold
|
||||||
|
|
||||||
|
C - Drop Call and Return to CC during trunking operation
|
||||||
|
L - Manual Cycle Forward Channel Tuned when RIGCTL or using RTL input and channel csv loaded
|
||||||
|
|
||||||
|
S - Toggle between EDACS Standard/Network and Extended Addressing mode (Capital S)
|
||||||
|
A - Toggle EDACS ESK Mask (none vs A0)
|
||||||
|
|
||||||
|
H - Toggle High Pass Filter on Digital Sythesized Voice
|
||||||
|
V - Toggle Low Pass Filter on Analog Voice or Raw Signal Monitoring
|
||||||
|
B - Toggle High Pass Filter on Analog Voice or Raw Signal Monitoring
|
||||||
|
N - Toggle Passband Filter on Analog Voice or Raw Signal Monitoring
|
||||||
|
|
||||||
|
[ - Scroll backwards through Event History
|
||||||
|
] - Scroll forwards through Event History
|
||||||
|
\ - Switch between Slot 1 and Slot 2 Event History
|
||||||
|
|
||||||
|
v - Cycle RTL Input Volume Multiplier 1X, 2X, 3X (lower v)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -270,3 +293,88 @@ where samples is 160 for mono, 320 for stereo, and short samples are 2 and float
|
|||||||
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
|
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
|
||||||
|
|
||||||
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
|
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
|
||||||
|
|
||||||
|
Note3: socat version 1.8 may have a `E xioopen_ipdgram_listen(): unknown address family 0` problem, downgrading to 1.7.4 is recommended if this occurs. `sudo downgrade socat`.
|
||||||
|
|
||||||
|
## Record 48k/1 audio with rtl_fm
|
||||||
|
|
||||||
|
You can record suitable audio to feed as input to dsd-fme with `-i` using rtl_fm:
|
||||||
|
|
||||||
|
`rtl_fm -M nfm -f [FREQ] -s 48k -g 42 -l 20 > input.wav`
|
||||||
|
|
||||||
|
You can also combine that with `socat` to send the audio to a remote dsd-fme instance in real time while keeping a local copy on the host where the RTL-SDR dongle is:
|
||||||
|
|
||||||
|
`rtl_fm -M fm -f [FREQ] -s 48k -g 42 -l 20 | tee input.wav | socat -u - TCP-LISTEN:1234,forever,reuseaddr`
|
||||||
|
|
||||||
|
On the remote side where dsd-fme is, use the TCP input:
|
||||||
|
|
||||||
|
`dsd-fme -i tcp:192.168.7.8:1234 -N`
|
||||||
|
|
||||||
|
Note: As always, when using rtl_fm, play with `-l` and `-g` to find a good squelch and gain values for your environment - you will know if the squelch is the right value when `input.wav` does not increase in size in the absence of useful signal on the monitored frequency.
|
||||||
|
|
||||||
|
## Using the Experimental M17 Encoder (and Decoder)
|
||||||
|
|
||||||
|
You can use the experimental M17 Voice Stream and Packet encoder with the following examples.
|
||||||
|
|
||||||
|
Encode/Decode Local Feedback Voice Stream (Single Session):
|
||||||
|
|
||||||
|
`dsd-fme -fZ -i pulse -o pulse -M M17:3:SP5WWP:BROADCAST:48000`
|
||||||
|
|
||||||
|
Using the `-8` option (raw audio monitor) will instead send encoded raw audio to output instead of decoded audio. For example,
|
||||||
|
|
||||||
|
To send a voice stream out of stdout into SOCAT TCP to a second/remote DSD-FME session to decode:
|
||||||
|
|
||||||
|
Encode (Upper Z):
|
||||||
|
|
||||||
|
`dsd-fme -fZ -8 -i pulse -M M17:9:LWVMOBILE:DSD-FME:48000 -o - | socat stdio tcp-listen:7355,forever,reuseaddr`
|
||||||
|
|
||||||
|
Decode (Lower z):
|
||||||
|
|
||||||
|
`dsd-fme -fz -i tcp:192.168.7.8:7355`
|
||||||
|
|
||||||
|
NOTE: When using tcp input for M17 decoding, DSD-FME will keep the TCP connection alive with constant retries, so no need to restart the decoding session on connection failure.
|
||||||
|
|
||||||
|
SMS Packet Encoder (Text Only):
|
||||||
|
|
||||||
|
`dsd-fme -fP -8 -S "This is a sample message sent over M17 Packet Data using DSD-FME to encode it."`
|
||||||
|
|
||||||
|
SMS Packet Encoder (over SOCAT TCP):
|
||||||
|
|
||||||
|
`dsd-fme -fP -8 -S "This is a sample message sent over M17 Packet Data using DSD-FME to encode it and SOCAT to send it over TCP." -o - | socat stdio tcp-listen:7355,forever,reuseaddr`
|
||||||
|
|
||||||
|
Many combinations of input and output can be used as well, and using features like raw audio saving with `-6 m17str.wav` will save a wav file of your encoded audio to be replayed later with `-i m17str.wav`
|
||||||
|
Also note, features function similarly, like -Z for payload, and input options include pulse, oss, stdin, rtl, tcp, etc, using those as the mic in for voice encoding. With the right setup of input/output/input using SOCAT TCP pipes, it is conceivable to use DSD-FME to convert analog audio from NFM into M17 audio, or even change another digital format supported by DSD-FME into M17 audio, if desired (purely for research and fun purposes). Ncurses terminal will function with internal encoder/decoder and wav file creation, with toggle encode/tx with `\` key, but will not function with stdout properly.
|
||||||
|
|
||||||
|
The `-M` switch is used to specify user M17 variables, the string is in the format of M17:CAN:SRC:DST:INPUT_RATE.
|
||||||
|
CAN 1-15; SRC and DST have to be no more than 9 UPPER base40 characters.
|
||||||
|
BASE40: ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.'
|
||||||
|
Input Rate Default is 48000; Use Multiples of 8000 up to 48000.
|
||||||
|
Values not entered into the M17: string are set to default values. M17:7:DSD-FME:DSD-FME:48000
|
||||||
|
|
||||||
|
Fun Example Transmuting OTA Analog Things into M17:
|
||||||
|
|
||||||
|
Start up in sequence.
|
||||||
|
|
||||||
|
Terminal #1 (RTL Input):
|
||||||
|
`dsd-fme -fZ -8 -M M17:1:ANALOG:M17:48000 -i rtl:0:162.425M -o - | socat stdio tcp-listen:7310,forever,reuseaddr`
|
||||||
|
|
||||||
|
Terminal #2:
|
||||||
|
`dsd-fme -fz -i tcp:127.0.0.1:7310`
|
||||||
|
|
||||||
|
Fun Example Transmuting OTA Digital Things into M17:
|
||||||
|
|
||||||
|
Start up all three of these in sequence.
|
||||||
|
|
||||||
|
Terminal #1 (connecting to SDR++):
|
||||||
|
`dsd-fme -fi -i tcp:127.0.0.1:7355 -o - | socat stdio tcp-listen:7300,forever,reuseaddr`
|
||||||
|
|
||||||
|
Terminal #2:
|
||||||
|
`dsd-fme -fZ -8 -M M17:2:NXDN:M17:8000 -i tcp:127.0.0.1:7300 -o - | socat stdio tcp-listen:7301,forever,reuseaddr`
|
||||||
|
|
||||||
|
Terminal #3:
|
||||||
|
`dsd-fme -fz -i tcp:127.0.0.1:7301`
|
||||||
|
|
||||||
|
Note: Transmuting only carries over voice when audio is output, and will not carry any ID values, or any other data payloads.
|
||||||
|
This mode is only meant for educational or fun purposes, please do not retransmit stuff that doesn't belong to you.
|
||||||
|
|
||||||
|
Information on this section will be updated as features are added or modified, etc. If you need help with a particular function and can't find a suitable answer, always open a new issue here, or make contact on the radio reference forum for additional examples, guidance, ideas, help, etc.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
## How to clone and build this branch
|
## How to clone and build this branch
|
||||||
|
|
||||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
### Ubuntu 22.04/20.04/LM20/Debian Bullseye:
|
||||||
|
|
||||||
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 23.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
|
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 23.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
|
||||||
|
|
||||||
@@ -8,16 +8,21 @@ If you need all dependencies build and installed first (only on Debian/Ubuntu/Mi
|
|||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install.sh
|
||||||
chmod +x download-and-install.sh
|
sh download-and-install.sh
|
||||||
./download-and-install.sh
|
```
|
||||||
|
|
||||||
|
### Debian 12 (SID) / Ubuntu 24.04 LTS (Updated Ncurses Dependencies)
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-ubuntu2404lts.sh
|
||||||
|
sh download-and-install-ubuntu2404lts.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Arch Based Distros:
|
### Arch Based Distros:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-Arch.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-Arch.sh
|
||||||
chmod +x download-and-install-Arch.sh
|
sh download-and-install-Arch.sh
|
||||||
./download-and-install-Arch.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Other:
|
### Other:
|
||||||
@@ -26,8 +31,7 @@ If you have dependencies already installed, please run this instead:
|
|||||||
|
|
||||||
```
|
```
|
||||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-nodeps.sh
|
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-nodeps.sh
|
||||||
chmod +x download-and-install-nodeps.sh
|
sh download-and-install-nodeps.sh
|
||||||
./download-and-install-nodeps.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Manual Install
|
## Manual Install
|
||||||
@@ -38,7 +42,10 @@ Debian/Mint/Ubuntu/Pi
|
|||||||
|
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
#Ubuntu 22.04 lts / Debian 11 and lower
|
||||||
|
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libcodec2-dev
|
||||||
|
#Ubuntu 24.04 lts / Debian 12
|
||||||
|
#sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncurses-dev libncurses6 libcodec2-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||||
@@ -53,8 +60,6 @@ Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/l
|
|||||||
```
|
```
|
||||||
sudo pacman -Syu
|
sudo pacman -Syu
|
||||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
|
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
|
||||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Headless Ubuntu Server/Pi
|
## Headless Ubuntu Server/Pi
|
||||||
@@ -62,24 +67,7 @@ sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
|||||||
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
|
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
|
||||||
```
|
|
||||||
|
|
||||||
### Build and Install ITPP - ONLY IF NOT IN REPO!!
|
|
||||||
|
|
||||||
```
|
|
||||||
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
|
||||||
tar xjf itpp*
|
|
||||||
#if you can't cd into this folder, double check folder name first
|
|
||||||
cd itpp-4.3.1
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make -j `nproc`
|
|
||||||
sudo make install
|
|
||||||
sudo ldconfig
|
|
||||||
cd ..
|
|
||||||
cd ..
|
|
||||||
```
|
```
|
||||||
|
|
||||||
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
|
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
|
||||||
@@ -98,22 +86,6 @@ cd ..
|
|||||||
cd ..
|
cd ..
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
|
||||||
|
|
||||||
```
|
|
||||||
cp libmbe* /usr/lib
|
|
||||||
cp cygmbe* /usr/lib
|
|
||||||
cp cygmbe* /bin
|
|
||||||
```
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo cp libmbe* /usr/lib
|
|
||||||
sudo cp cygmbe* /usr/lib
|
|
||||||
sudo cp cygmbe* /bin
|
|
||||||
```
|
|
||||||
|
|
||||||
Finish by running these steps to clone and build DSD-FME.
|
Finish by running these steps to clone and build DSD-FME.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -128,34 +100,42 @@ sudo ldconfig
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### LD_PATH
|
||||||
|
|
||||||
|
Some environments may require an LD path to be set to /usr/local/lib, similar to:
|
||||||
|
```
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
export LD_LIBRARY_PATH
|
||||||
|
```
|
||||||
|
|
||||||
### Windows Cygwin Builds
|
### Windows Cygwin Builds
|
||||||
|
|
||||||
If using RTL input support, you must install libusb-win32 before proceeding with Cygwin installation. You will also need to build and compile a version of librtlsdr, but this can be tricky, and personally, I had to resort to using a much older version of the source code to get it to build at all with the rtl support in the precompiled 'Aero' builds.
|
Cygwin builds now have an experimental semi-automatic installer, to run, follow steps below:
|
||||||
|
|
||||||
Then install all dependencies available in the repo prior to building, either directly selecting them during setup with the setup-x86.exe or setup-x64.exe or by issuing a command similar to this:
|
Open Windows PowerShell (not Command Prompt) and copy and paste all of this in all at once.
|
||||||
|
|
||||||
```
|
```
|
||||||
setup-x64.exe --packages libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,xfce-pulseaudio-plugin,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,unzip,wget,gcc-g++,libsndfile-devel
|
Invoke-WebRequest https://cygwin.com/setup-x86_64.exe -OutFile setup-x86_64.exe
|
||||||
```
|
.\setup-x86_64.exe --packages nano,libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,zip,unzip,wget,gcc-g++,libsndfile-devel
|
||||||
|
|
||||||
Then manually install ITPP and MBElib, see above install notes. Be sure to run `cp libmbe* /usr/lib` after compiling MBElib.
|
|
||||||
|
|
||||||
Then you can build and install using
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/lwvmobile/dsd-fme
|
|
||||||
cd dsd-fme
|
Pick a Mirror. http://www.gtlib.gatech.edu mirror seems relatively fast. Nurse the Cygwin installer by clicking next and waiting for it to finish. Ignore the warning popup telling you to install libusb from sourceforge. Install the [Zadig](https://zadig.akeo.ie/ "Zadig") driver instead, if you haven't already and have an RTL Dongle. After Cygwin finishes installing, the installer sh script will download and run, be patient, it may also take a little while.
|
||||||
mkdir build
|
|
||||||
cd build
|
Then:
|
||||||
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
|
||||||
cmake -DAERO=ON ..
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
```
|
```
|
||||||
|
C:\cygwin64\bin\mintty.exe /bin/bash -l -c "wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/refs/heads/audio_work/download-and-install-cygwin.sh; sh download-and-install-cygwin.sh; dsd-fme;"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
After the sh script finishes, dsd-fme should open. If not, then double click on the Cygwin Terminal desktop shortcut, and try running `dsd-fme`. If you chose to create a portable version, you will find the folder and zip file in the `C:\cygwin64\home\username` directory if using the default cygwin64 folder location.
|
||||||
|
|
||||||
|
You can also update your versions by using the cyg_rebuild.sh script `sh cyg_rebuild.sh`.
|
||||||
|
|
||||||
### Virtual Sinks
|
### Virtual Sinks
|
||||||
|
|
||||||
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input.
|
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input. You may need to manually install either of these programs manually, if desired, or find suitable alternatives for pipewire-pulse such as pwvucontrol, or similar.
|
||||||
|
|
||||||
```
|
```
|
||||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||||
|
|||||||
14
examples/cygwin_bat/9pa-close-pulse-audio-server.bat.old
Normal file
14
examples/cygwin_bat/9pa-close-pulse-audio-server.bat.old
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@REM Shutdown pulseaudio and clean out any remenants in /dev/shm if left behind
|
||||||
|
|
||||||
|
cd dsd-fme
|
||||||
|
pactl.exe exit
|
||||||
|
|
||||||
|
@REM now navigate to the /dev/shm folder and automatically remove any
|
||||||
|
@REM remnants from other times pulse wasn't shut down properly
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
cd dev
|
||||||
|
cd shm
|
||||||
|
del pulse*
|
||||||
|
|
||||||
|
PAUSE
|
||||||
34
examples/cygwin_bat/9pa-start-pulse-audio-server.bat.old
Normal file
34
examples/cygwin_bat/9pa-start-pulse-audio-server.bat.old
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
@REM Set the console / terminal to 90 columns, 50 lines
|
||||||
|
@REM mode con: cols=90 lines=50
|
||||||
|
|
||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
@REM change directory into the dsd-fme folder
|
||||||
|
cd dsd-fme
|
||||||
|
|
||||||
|
@REM Start the Pulse Audio backend with a 10 minute time out
|
||||||
|
@REM start pulse audio server with 600 second idle time and no CPU limit (prevent closing while idle in menu)
|
||||||
|
|
||||||
|
@REM output from pulse server routed to NUL to supress "capabilities dropped, nag messages, etc" messages
|
||||||
|
pulseaudio.exe --start --no-cpu-limit=TRUE --exit-idle-time=600 2> NUL
|
||||||
|
|
||||||
|
@REM End pulse start up
|
||||||
|
|
||||||
|
ECHO The Pulse Audio Server should now be active!
|
||||||
|
|
||||||
|
@REM Setup Some null-sinks (if desired, remove @REM below)
|
||||||
|
|
||||||
|
@REM pactl load-module module-null-sink sink_name=virtual_sink1 sink_properties=device.description=Virtual_Sink1
|
||||||
|
@REM pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||||
|
|
||||||
|
@REM Setup Default Sink to device 0 (output)
|
||||||
|
|
||||||
|
pactl set-default-sink 0
|
||||||
|
|
||||||
|
@REM List Avaiable Pulse Audio Sinks and Sources
|
||||||
|
|
||||||
|
@ECHO ON
|
||||||
|
|
||||||
|
dsd-fme -O
|
||||||
|
|
||||||
|
PAUSE
|
||||||
224
examples/cygwin_bat/complete_usage_options.txt
Normal file
224
examples/cygwin_bat/complete_usage_options.txt
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
Build Version: AW 2025-209-g14edf32
|
||||||
|
MBElib Version: 1.3.4
|
||||||
|
CODEC2 Support Enabled
|
||||||
|
|
||||||
|
Usage: dsd-fme [options] Decoder/Trunking Mode
|
||||||
|
or: dsd-fme [options] -r <files> Read/Play saved mbe data from file(s)
|
||||||
|
or: dsd-fme -h Show help
|
||||||
|
|
||||||
|
Display Options:
|
||||||
|
-N Use NCurses Terminal
|
||||||
|
dsd-fme -N 2> console_log.txt
|
||||||
|
-Z Log MBE/PDU Payloads to console
|
||||||
|
|
||||||
|
Device Options:
|
||||||
|
-O List All Pulse Audio Input Sources and Output Sinks (devices).
|
||||||
|
|
||||||
|
Input/Output options:
|
||||||
|
-i <device> Audio input device (default is pulse)
|
||||||
|
/dev/dsp for OSS audio (Depreciated: Will require padsp wrapper in Linux)
|
||||||
|
pulse for pulse audio signal input
|
||||||
|
pulse:6 or pulse:virtual_sink2.monitor for pulse audio signal input on virtual_sink2 (see -O)
|
||||||
|
rtl for rtl dongle (Default Values -- see below)
|
||||||
|
rtl:dev:freq:gain:ppm:bw:sq:vol for rtl dongle (see below)
|
||||||
|
tcp for tcp client SDR++/GNURadio Companion/Other (Port 7355)
|
||||||
|
tcp:192.168.7.5:7355 for custom address and port
|
||||||
|
filename.bin for OP25/FME capture bin files
|
||||||
|
filename.wav for 48K/1 wav files (SDR++, GQRX)
|
||||||
|
filename.wav -s 96000 for 96K/1 wav files (DSDPlus)
|
||||||
|
(Use single quotes '/directory/audio file.wav' when directories/spaces are present)
|
||||||
|
-s <rate> Sample Rate of wav input files (48000 or 96000) Mono only!
|
||||||
|
-o <device> Audio output device (default is pulse)
|
||||||
|
/dev/dsp for OSS audio (Depreciated: Will require padsp wrapper in Linux)
|
||||||
|
pulse for pulse audio decoded voice or analog output
|
||||||
|
pulse:1 or pulse:alsa_output.pci-0000_0d_00.3.analog-stereo for pulse audio decoded voice or analog output on device (see -O)
|
||||||
|
null for no audio output
|
||||||
|
udp for UDP socket blaster output (default host 127.0.0.1; default port 23456)
|
||||||
|
udp:192.168.7.8:23470 for UDP socket blaster output (Target Address and Port
|
||||||
|
-d <dir> Create mbe data files, use this directory (TDMA version is experimental)
|
||||||
|
-r <files> Read/Play saved mbe data from file(s)
|
||||||
|
-g <float> Audio Digital Output Gain (Default: 0 = Auto; )
|
||||||
|
(Manual: 1 = 2%; 50 = 100%)
|
||||||
|
-n <float> Audio Analog Output Gain (Default: 0 = Auto; 0-100% )
|
||||||
|
-6 <file> Output raw audio .wav file (48K/1). (WARNING! Large File Sizes 1 Hour ~= 360 MB)
|
||||||
|
-7 <dir> Create/Use Custom directory for Per Call decoded .wav file saving.
|
||||||
|
(Use ./folder for Nested Directory!)
|
||||||
|
(Use /path/to/folder for hard coded directory!)
|
||||||
|
(Use Before the -P option!)
|
||||||
|
-8 Enable Source Audio Monitor
|
||||||
|
(Set Squelch in RTL, SDR++ or GQRX, etc, if monitoring mixed analog/digital)
|
||||||
|
-w <file> Output synthesized speech to a single static .wav file. (Do not use with -P Per Call Switch)
|
||||||
|
-P Enable Per Call WAV file saving. (Do not use with -w filename.wav single wav file switch)
|
||||||
|
(Per Call works with everything now and doesn't require ncurses terminal!)
|
||||||
|
-a Enable Call Alert Beep
|
||||||
|
(Warning! Might be annoying.)
|
||||||
|
-J <file> Specify Filename for Event Log Output.
|
||||||
|
-L <file> Specify Filename for LRRP Data Output.
|
||||||
|
-Q <file> Specify Filename for OK-DMRlib Structured File Output. (placed in DSP folder)
|
||||||
|
-Q <file> Specify Filename for M17 Float Stream Output. (placed in DSP folder)
|
||||||
|
-c <file> Output symbol capture to .bin file
|
||||||
|
-q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice
|
||||||
|
-V <num> Enable TDMA Voice Synthesis on Slot 1 (1), Slot 2 (2), or Both (3); Default is 3;
|
||||||
|
-z Set TDMA Voice Slot Preference when using /dev/dsp audio output (prevent lag and stuttering)
|
||||||
|
-y Enable Experimental Pulse Audio Float Audio Output
|
||||||
|
-v <hex> Set Filtering Bitmap Options (Advanced Option)
|
||||||
|
1 1 1 1 (0xF): PBF/LPF/HPF/HPFD on
|
||||||
|
|
||||||
|
RTL-SDR options:
|
||||||
|
Usage: rtl:dev:freq:gain:ppm:bw:sq:vol
|
||||||
|
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
||||||
|
dev <num> RTL-SDR Device Index Number or 8 Digit Serial Number, no strings! (default 0)
|
||||||
|
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||||
|
gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)
|
||||||
|
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||||
|
bw <num> RTL-SDR Bandwidth kHz (default = 12)(4, 6, 8, 12, 16, 24)
|
||||||
|
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||||
|
vol <num> RTL-SDR Sample 'Volume' Multiplier (default = 2)(1,2,3)
|
||||||
|
Example: dsd-fme -fs -i rtl -C cap_plus_channel.csv -T
|
||||||
|
Example: dsd-fme -fp -i rtl:0:851.375M:22:-2:24:0:2
|
||||||
|
|
||||||
|
Decoder options:
|
||||||
|
-fa Auto Detection
|
||||||
|
-fA Passive Analog Audio Monitor
|
||||||
|
-ft TDMA Trunking P25p1 Control and Voice, P25p2 Trunked Channels, and DMR
|
||||||
|
-fs DMR TDMA BS and MS Simplex
|
||||||
|
-f1 Decode only P25 Phase 1
|
||||||
|
-f2 Decode only P25 Phase 2 (6000 sps) **
|
||||||
|
-fd Decode only DSTAR
|
||||||
|
-fx Decode only X2-TDMA
|
||||||
|
-fy Decode only YSF
|
||||||
|
-fz Decode only M17*
|
||||||
|
-fi Decode only NXDN48* (6.25 kHz) / IDAS*
|
||||||
|
-fn Decode only NXDN96* (12.5 kHz)
|
||||||
|
-fp Decode only ProVoice*
|
||||||
|
-fh Decode only EDACS Standard/ProVoice*
|
||||||
|
-fH Decode only EDACS Standard/ProVoice with ESK 0xA0*
|
||||||
|
-fh344 Decode only EDACS Standard/ProVoice and set AFS to 344 or similar custom 11-bit scheme*
|
||||||
|
-fH434 Decode only EDACS Standard/ProVoice and set AFS to custom 11-bit scheme with ESK 0xA0*
|
||||||
|
-fe Decode only EDACS EA/ProVoice*
|
||||||
|
-fE Decode only EDACS EA/ProVoice with ESK 0xA0*
|
||||||
|
-fm Decode only dPMR*
|
||||||
|
-l Disable DMR, dPMR, NXDN, M17 input filtering
|
||||||
|
-u <num> Unvoiced speech quality (default=3)
|
||||||
|
-xx Expect non-inverted X2-TDMA signal
|
||||||
|
-xr Expect inverted DMR signal
|
||||||
|
-xd Expect inverted ICOM dPMR signal
|
||||||
|
|
||||||
|
* denotes frame types that cannot be auto-detected.
|
||||||
|
** Phase 2 Single Frequency may require user to manually set WACN/SYSID/CC parameters if MAC_SIGNAL not present.
|
||||||
|
|
||||||
|
Advanced Decoder options:
|
||||||
|
-X <hex> Manually Set P2 Parameters (WACN, SYSID, CC/NAC)
|
||||||
|
(-X BEE00ABC123)
|
||||||
|
-_ <dec> Manually Set NXDN PN95 Dibit Scrambler Seed (1-511)
|
||||||
|
(-* 261)
|
||||||
|
-D <dec> Manually Set TIII DMR Location Area n bit len (0-10)(10 max)
|
||||||
|
(Value defaults to max n bit value for site model size)
|
||||||
|
(Setting 0 will show full Site ID, no area/subarea)
|
||||||
|
|
||||||
|
-ma Auto-select modulation optimizations
|
||||||
|
-mc Use only C4FM modulation optimizations (default)
|
||||||
|
-mg Use only GFSK modulation optimizations
|
||||||
|
-mq Use only QPSK modulation optimizations
|
||||||
|
-m2 Use P25p2 6000 sps QPSK modulation optimizations
|
||||||
|
-F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail
|
||||||
|
Use this feature to allow MAC_SIGNAL even if CRC errors.
|
||||||
|
-F Relax DMR RAS/CRC CSBK/DATA Pass/Fail
|
||||||
|
Enabling on some systems could lead to bad channel assignments/site data decoding if bad or marginal signal
|
||||||
|
|
||||||
|
-b <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)
|
||||||
|
(NOTE: This used to be the 'K' option!)
|
||||||
|
|
||||||
|
-H <hex> Manually Enter Hytera 10/32/64 Char Basic Privacy Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-H 0B57935150
|
||||||
|
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
|
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||||
|
|
||||||
|
-H <hex> Manually Enter AES-128, AES-256, or Kirisun-256 Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-H '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
|
-H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8'
|
||||||
|
|
||||||
|
-R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)
|
||||||
|
|
||||||
|
-1 <hex> Manually Enter RC4 or DES Key Value (DMR, P25, NXDN) (Hex Value)
|
||||||
|
|
||||||
|
-2 <hex> Manually Enter and Enforce TYT 16-bit BP Key Value (DMR) (Hex Value)
|
||||||
|
|
||||||
|
-! <hex> Manually Enter and Enforce TYT Advanced Privacy (PC4) 128 or 256 bit AP Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-! '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
|
-! '1111111111111111 1111111111111111 1111111111111111 1111111111111111'
|
||||||
|
|
||||||
|
-@ <hex> Manually Enter and Enforce Retevis Advanced Privacy (RC2) 128 or 256 bit AP Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-@ '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
|
-@ '1122334455667788 99AABBCCDDEEFF11 1122334455667788 99AABBCCDDEEFF11'
|
||||||
|
|
||||||
|
-5 <hex> Manually Enter and Enforce TYT Enhanced Privacy (AES-128) EP Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-5 '736B9A9C5645288B 243AD5CB8701EF8A'
|
||||||
|
|
||||||
|
-+ <hex> Manually Enter and Enforce Baofeng Advanced Privacy (PC5-128 or PC5-256) AP Hex Key (see example below)
|
||||||
|
Encapulate in Single Quotation Marks; Space every 16 chars.
|
||||||
|
-+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC'
|
||||||
|
-+ 'ABCDABCDABCDABCD ABDCDABCDABCDABC EF01EF01EF01EF01 EF01EF01EF01EF01'
|
||||||
|
|
||||||
|
-^ <hex> Manually Enter and Enforce Connect Systems 72-bit (9-byte) Extended Encryption Hex Key (see example below)
|
||||||
|
-^ 3BBE782C0430008271
|
||||||
|
|
||||||
|
-9 <dec> Manually Enter and Enforce Kenwood 15-bit Scrambler Key Value (DMR) (Dec Value)
|
||||||
|
|
||||||
|
-A <hex> Manually Enter and Enforce Anytone 16-bit BP Key Value (DMR) (Hex Value)
|
||||||
|
|
||||||
|
-S <str> Manually Enter and Enforce Generic Static Keystream -> Length and BYTE PACKED / ALIGNED String for AMBE (up to 882 bits)
|
||||||
|
For Example, enter 16-bit Keystream 0909 as:
|
||||||
|
-S 16:0909
|
||||||
|
For Example, enter 49-bit Keystream as:
|
||||||
|
-S 49:123456789ABC80
|
||||||
|
For Example, enter 49-bit Keystream (MBP 70) as:
|
||||||
|
-S 49:ED0AED4AED4AED4A
|
||||||
|
For Example, Baofeng 49-bit Keystream for 56-bit Custom Encryption as:
|
||||||
|
-S 49:11AA22BB33CC44
|
||||||
|
|
||||||
|
-k <file> Import Key List from csv file (Decimal Format) -- Lower Case 'k'.
|
||||||
|
Only supports NXDN, DMR Basic Privacy (decimal value).
|
||||||
|
(dPMR and Hytera 32/64 char not supported, DMR uses TG value as key id -- EXPERIMENTAL!!).
|
||||||
|
|
||||||
|
-K <file> Import Key List from csv file (Hexidecimal Format) -- Capital 'K'.
|
||||||
|
Use for Hex Value Hytera 10-char BP keys, RC4 10-char, DES 16-char Hex Keys, and AES128/256 32/64-char keys.
|
||||||
|
|
||||||
|
-4 Force Privacy Key over Encryption Identifiers (DMR MBP/HBP and NXDN Scrambler)
|
||||||
|
|
||||||
|
-0 Force RC4 Key over Missing PI header/LE Encryption Identifiers (DMR)
|
||||||
|
|
||||||
|
-M <hex> Force Entered Alg ID Value over Missing PI header/LE Encryption Identifiers (DMR)
|
||||||
|
|
||||||
|
-3 Disable DMR Late Entry Encryption Identifiers (VC6 Single Burst)
|
||||||
|
Note: Disable this if false positives on Voice ENC occur.
|
||||||
|
|
||||||
|
Trunking Options:
|
||||||
|
-C <file> Import Channel to Frequency Map (channum, freq) from csv file. (Capital C)
|
||||||
|
(See channel_map.csv for example)
|
||||||
|
-G <file> Import Group List Allow/Block and Label from csv file.
|
||||||
|
(See group.csv for example)
|
||||||
|
-T Enable Trunking Features (NXDN/P25/EDACS/DMR) with RIGCTL/TCP or RTL Input
|
||||||
|
-Y Enable Scanning Mode with RIGCTL/TCP or RTL Input
|
||||||
|
Experimental -- Can only scan for sync with enabled decoders, don't mix NXDN and DMR/P25!
|
||||||
|
This is not a Trunking Feature, just scans through conventional frequencies fast!
|
||||||
|
-W Use Imported Group List as a Trunking Allow/White List -- Only Tune with Mode A
|
||||||
|
-p Disable Tune to Private Calls (DMR TIII, P25, NXDN Type-C and Type-D)
|
||||||
|
-E Disable Tune to Group Calls (DMR TIII, Con+, Cap+, P25, NXDN Type-C, and Type-D)
|
||||||
|
-e Enable Tune to Data Calls (DMR TIII, Cap+, NXDN Type-C)
|
||||||
|
(NOTE: No Clear Distinction between Cap+ Private Voice Calls and Data Calls -- Both enabled with Data Calls
|
||||||
|
-I <dec> Specify TG to Hold During Trunking (DMR, P25, NXDN Type-C Trunking)
|
||||||
|
-U <port> Enable RIGCTL/TCP; Set TCP Port for RIGCTL. (4532 on SDR++)
|
||||||
|
-B <Hertz> Set RIGCTL Setmod Bandwidth in Hertz (0 - default - OFF)
|
||||||
|
P25 - 12000; NXDN48 - 7000; NXDN96: 12000; DMR - 7000-12000; EDACS/PV - 12000-24000;
|
||||||
|
May vary based on system stregnth, etc.
|
||||||
|
-t <secs> Set Trunking or Scan Speed VC/sync loss hangtime in seconds. (default = 1 second)
|
||||||
|
|
||||||
|
Trunking Example TCP: dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.txt
|
||||||
|
Trunking Example RTL: dsd-fme -fs -i rtl:0:450M:26:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.txt
|
||||||
|
|
||||||
97
examples/cygwin_bat/example_options.txt
Normal file
97
examples/cygwin_bat/example_options.txt
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
This example options contains numerous options put into the start-dsd-fme.bat file in the option string
|
||||||
|
feel free to experiment and mix and match example options for your bat files option string.
|
||||||
|
|
||||||
|
Trunking Option Examples:
|
||||||
|
|
||||||
|
P25 (Phase 1 Control) Trunking with SDR++ Network Sink input, RIGCTL, /dev/dsp output,
|
||||||
|
per call wav files, ncurses terminal
|
||||||
|
-ft -i tcp:127.0.0.1:7355 -U 4532 -T -P -N
|
||||||
|
|
||||||
|
P25 (Phase 2 Control) Trunking with SDR++ Network Sink input, RIGCTL, /dev/dsp output,
|
||||||
|
per call wav files, ncurses terminal
|
||||||
|
-f2 -i tcp:127.0.0.1:7355 -U 4532 -T -P -N
|
||||||
|
|
||||||
|
DMR Trunking with RTL input, /dev/dsp output, channel map import,
|
||||||
|
per call wav files, ncurses terminal, payload dump to console
|
||||||
|
-fs -i rtl:0:450M:0:-2:12 -T -C examples\dmr_t3_chan.csv -P -N -Z
|
||||||
|
|
||||||
|
DMR Trunking with SDR++ input, RIGCTL, /dev/dsp output, RAS enabled CSBK (-F),
|
||||||
|
channel map import, per call wav files, ncurses terminal, payload dump to console
|
||||||
|
-fs -F -i tcp -U 4532 -T -C examples\capacity_plus_chan.csv -P -N -Z
|
||||||
|
|
||||||
|
NXDN48 v2.0 DFA (Direct Frequency Assignment) Trunking with SDR++ input, RIGCTL, /dev/dsp output,
|
||||||
|
scrambler key import (decimal), per call wav files, ncurses terminal, payload dump to console
|
||||||
|
-fi -i tcp -U 4532 -T -P -N -Z -k examples\nxdn_sc_key.csv
|
||||||
|
|
||||||
|
NXDN96 Trunking with SDR++ input, RIGCTL, /dev/dsp output,
|
||||||
|
channel map import, per call wav files, ncurses terminal, payload dump to console
|
||||||
|
-fn -i tcp -U 4532 -T -C examples\nxdn_chan_map.csv -P -N -Z
|
||||||
|
|
||||||
|
EDACS Standard Network Analog and Digital
|
||||||
|
-fh -i tcp -U 4532 -T -C edacs_channel_map.csv -G group.csv -N
|
||||||
|
-fh -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N
|
||||||
|
|
||||||
|
EDACS Extended Address Analog and Digital (with ESK)
|
||||||
|
-fE -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N
|
||||||
|
-fE -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N
|
||||||
|
|
||||||
|
Scanning Option Examples:
|
||||||
|
|
||||||
|
Scanning will not perform quickly like a real scanner, but can be used with any
|
||||||
|
supported decoding type and analog as well, and will require a channel_map to scan frequencies
|
||||||
|
channel numbers do not matter, but use unique ones for each frequeny
|
||||||
|
-t 0 will scan as fast as possible, but may miss frame sync, -t 1 is stable, but needs 1 second between tuning
|
||||||
|
|
||||||
|
P25/DMR/Analog Scanning with RTL input, /dev/dsp output, channel map import,
|
||||||
|
per call wav files, ncurses terminal, payload dump to console, raw audio signal monitoring
|
||||||
|
-ft -i rtl:0:450M:0:-2:12 -Y -t 1 -C examples\dmr_t3_chan.csv -P -8 -N -Z
|
||||||
|
|
||||||
|
P25/DMR/Analog Scanning with SDR++ input (use squelch), RIGCTL, /dev/dsp output, channel map import,
|
||||||
|
per call wav files, ncurses terminal, payload dump to console, raw audio signal monitoring
|
||||||
|
-ft -i tcp:127.0.0.1:7355 -U 4532 -Y -t 1 -C examples\dmr_t3_chan.csv -P -8 -N -Z
|
||||||
|
|
||||||
|
NXDN48/Analog Scanning with SDR++ input (use squelch), RIGCTL, /dev/dsp output, channel map import,
|
||||||
|
per call wav files, ncurses terminal, payload dump to console, raw audio signal monitoring
|
||||||
|
-fi -i tcp:127.0.0.1:7355 -U 4532 -Y -t 1-C examples\nxdn_chan_map.csv -P -8 -N -Z
|
||||||
|
|
||||||
|
Analog Scanning with SDR++ input (use squelch), RIGCTL, /dev/dsp output, channel map import
|
||||||
|
-fA -i tcp:127.0.0.1:7355 -U 4532 -Y -t 0 -C examples\nxdn_chan_map.csv -8
|
||||||
|
|
||||||
|
Encryption Option Examples:
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, use basic privacy key 70
|
||||||
|
-fs -b 70
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, load .csv file with decimal basic privacy keys loaded by TG value,
|
||||||
|
-fs -k examples\multi_key.csv
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, use Hytera basic privacy key (10, 32, and 64 hex char versions)
|
||||||
|
-fs -H 1111111111
|
||||||
|
-fs -H '2222222222222222 3333333333333333'
|
||||||
|
-fs -H '2222222222222222 3333333333333333 4444444444444444 5555555555555555'
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, use RC4 key 0x7777777777
|
||||||
|
-fs -1 7777777777
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, use RC4 key 0x7777777777,
|
||||||
|
Force RC4 Key over Missing PI header/LE Encryption Identifiers (-0)
|
||||||
|
Disable Late Entry Encryption Signalling Identifiers (-3)
|
||||||
|
-fs -0 -3 -1 7777777777
|
||||||
|
|
||||||
|
DMR with default /dev/dsp input and output, load RC4 and 10-char HBP keys from .csv file (hexidecimal format)
|
||||||
|
-fs -K dsd-fme\examples\multi_key_hex.csv
|
||||||
|
|
||||||
|
P25 with default /dev/dsp input and output, use RC4 key 0x7777777777
|
||||||
|
-ft -1 7777777777
|
||||||
|
|
||||||
|
NXDN48 with default /dev/dsp input and output, use Scrambler key 32767
|
||||||
|
-fi -R 32767
|
||||||
|
|
||||||
|
NXDN96 with default /dev/dsp input and output, use Scrambler key 15000
|
||||||
|
-fn -R 15000
|
||||||
|
|
||||||
|
dPMR with default /dev/dsp input and output, use Scrambler key 32767
|
||||||
|
-fm -R 32767
|
||||||
|
|
||||||
|
NXDN48 with default /dev/dsp input and output, load scrambler keys from .csv file (decimal format)
|
||||||
|
-fi -k dsd-fme\examples\nxdn_sc_key.csv
|
||||||
1
examples/cygwin_bat/readme_cygwin_bat.txt
Normal file
1
examples/cygwin_bat/readme_cygwin_bat.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
These .bat files are ONLY for use on the portable cygwin builds, do not use these in any other build environments!
|
||||||
74
examples/cygwin_bat/start-dsd-fme.bat
Normal file
74
examples/cygwin_bat/start-dsd-fme.bat
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
@REM Digital Speech Decoder: Florida Man Edition
|
||||||
|
@REM DSD-FME Cygwin Windows Portable Builds
|
||||||
|
@REM
|
||||||
|
@REM The source code of this software can be downloaded here:
|
||||||
|
@REM https://github.com/lwvmobile/dsd-fme
|
||||||
|
@REM
|
||||||
|
@REM If you paid for, or were otherwise fleeced for this software, DEMAND YOUR MONEY BACK!
|
||||||
|
@REM
|
||||||
|
@REM This software is designed to be used with an SDR receiver (like SDR++ or SDR#) with TCP input,
|
||||||
|
@REM RTL Input, media file playback over virtual cables or null-sinks, or a Discriminator Tap input
|
||||||
|
@REM
|
||||||
|
@REM The complete options list can be seen by viewing complete_usage_options.txt
|
||||||
|
@REM Many examples can be found in example_options.txt
|
||||||
|
@REM
|
||||||
|
@REM Enjoy!
|
||||||
|
|
||||||
|
@REM Regarding the options string (or any string in .bat files)
|
||||||
|
@REM If your string may contain spaces, set the first '"' before options, and then an ending '"'
|
||||||
|
@REM Incorrect: set options="-fs -N -Z"
|
||||||
|
@REM Correct: set "options=-fs -N -Z"
|
||||||
|
|
||||||
|
@REM set options to pass to dsd-fme
|
||||||
|
set "options= -N -Z "
|
||||||
|
|
||||||
|
@REM Set Date Time for log (sourced from: https://stackoverflow.com/questions/1192476/format-date-and-time-in-a-windows-batch-script)
|
||||||
|
@echo off
|
||||||
|
REM "%date: =0%" replaces spaces with zeros
|
||||||
|
set d=%date: =0%
|
||||||
|
REM "set yyyy=%d:~-4%" pulls the last 4 characters
|
||||||
|
set yyyy=%d:~-4%
|
||||||
|
set mm=%d:~4,2%
|
||||||
|
set dd=%d:~7,2%
|
||||||
|
set dow=%d:~0,3%
|
||||||
|
set d=%yyyy%%mm%%dd%
|
||||||
|
|
||||||
|
set t=%TIME: =0%
|
||||||
|
REM "%t::=%" removes semi-colons
|
||||||
|
REM Instead of above, you could use "%t::=-%" to
|
||||||
|
REM replace semi-colons with hyphens (or any
|
||||||
|
REM non-special character)
|
||||||
|
set t=%t::=%
|
||||||
|
set t=%t:.=%
|
||||||
|
|
||||||
|
set datetimestr=%d%_%t%
|
||||||
|
@REM @echo Long date time str = %datetimestr%
|
||||||
|
|
||||||
|
@REM random number is used so that two log files don't share the same name
|
||||||
|
set rnd=%RANDOM%
|
||||||
|
|
||||||
|
@REM set log file relative filepath
|
||||||
|
set "clog=.\logs\console_log_%datetimestr%_%rnd%.txt"
|
||||||
|
set "elog=.\logs\event_log_%datetimestr%_%rnd%.txt"
|
||||||
|
|
||||||
|
@REM create the log file now with touch
|
||||||
|
.\dsd-fme\touch.exe %clog%
|
||||||
|
.\dsd-fme\touch.exe %elog%
|
||||||
|
|
||||||
|
@REM Launch Tail to display the console log and event log in a seperate console windows
|
||||||
|
start .\dsd-fme\tail.exe -n 40 -f %clog%
|
||||||
|
start .\dsd-fme\tail.exe -n 40 -f %elog%
|
||||||
|
|
||||||
|
@REM start dsd-fme with options and logs
|
||||||
|
.\dsd-fme\dsd-fme.exe %options% -J %elog% 2> %clog%
|
||||||
|
|
||||||
|
echo ----------------------------------------------------------------------------------
|
||||||
|
echo ----------------------------------------------------------------------------------
|
||||||
|
echo For any errors, see: %clog%
|
||||||
|
echo Forward %clog% and Options: "%options%"
|
||||||
|
echo to developer on Github or Radio Reference for troubleshooting.
|
||||||
|
echo ----------------------------------------------------------------------------------
|
||||||
|
echo ----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM Set pause to diplay above message
|
||||||
|
PAUSE
|
||||||
7
examples/example_aes_keys.csv
Normal file
7
examples/example_aes_keys.csv
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
keyid(hex), keyvalue(hex)
|
||||||
|
0001,0000000000000000,0000000000000000,0000000000000000,0000002823d87923
|
||||||
|
0003,0101010101010101,0101010101010101
|
||||||
|
0004,0101010101010101,0101010101010101,0101010101010101,0101010101010101
|
||||||
|
C197,A753BC945DE5E0F1,EC1970F8565154E6,D9DF2FAC6278FA93,B531D2CC046E93A2
|
||||||
|
0067,0000000000000000,0000000000000000,0000000000000000,DEADBEEFBAADF00D
|
||||||
|
0000,0000000000000000,0000000000000000,0000000000000000,0000000000000001
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
|
DEC,Mode(A- Allow; B - Block; DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
|
||||||
100,B,Example Name,Tag
|
100,B,Example Name,Tag
|
||||||
1449,A,Fire Dispatch,Fire
|
1449,A,Fire Dispatch,Fire
|
||||||
929,A,Fire Tac,Fire
|
929,A,Fire Tac,Fire
|
||||||
|
|||||||
|
BIN
examples/pavucontrol_plumbing1.png
Normal file
BIN
examples/pavucontrol_plumbing1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
examples/pavucontrol_plumbing2.png
Normal file
BIN
examples/pavucontrol_plumbing2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
112
examples/start-dsd-fme-linux-terminal.sh
Normal file
112
examples/start-dsd-fme-linux-terminal.sh
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Force bash for better compatibility (I think)
|
||||||
|
#
|
||||||
|
# Digital Speech Decoder: Florida Man Edition
|
||||||
|
#
|
||||||
|
# The source code of this software can be downloaded here:
|
||||||
|
# https://github.com/lwvmobile/dsd-fme
|
||||||
|
#
|
||||||
|
# If you paid for, or were otherwise fleeced for this software, DEMAND YOUR MONEY BACK!
|
||||||
|
#
|
||||||
|
# This software is designed to be used with an SDR receiver (like SDR++ or SDR#) with TCP input,
|
||||||
|
# RTL Input, media file playback over virtual cables or null-sinks, or a Discriminator Tap input
|
||||||
|
#
|
||||||
|
# The complete options list can be seen by viewing complete_usage_options.ans
|
||||||
|
# Many examples can be found in example_options.ans
|
||||||
|
#
|
||||||
|
# Enjoy!
|
||||||
|
###
|
||||||
|
#### IMPORTANT! Set your dsd-fme options here! ####
|
||||||
|
# Example : opts=' -ft -i rtl:0:460.350M:0:-1:8 -N -Z '
|
||||||
|
####
|
||||||
|
# set options to pass to dsd-fme
|
||||||
|
opts=' -N -Z '
|
||||||
|
####
|
||||||
|
# Initialize variables
|
||||||
|
xe="0"
|
||||||
|
gt="0"
|
||||||
|
xt="0"
|
||||||
|
ko="0"
|
||||||
|
# Functions to check for available terminals
|
||||||
|
chk_xe(){
|
||||||
|
# Check if x-terminal-emulator is installed
|
||||||
|
xe=$(which x-terminal-emulator 2>/dev/null)
|
||||||
|
if [ -z $xe ];then xe="0";else xe="1";fi
|
||||||
|
}
|
||||||
|
chk_gt(){
|
||||||
|
# Check if gnome-terminal is installed
|
||||||
|
gt=$(which gnome-terminal 2>/dev/null)
|
||||||
|
if [ -z $gt ];then gt="0";else gt="1";fi
|
||||||
|
}
|
||||||
|
chk_ko(){
|
||||||
|
# Check if Konsole is installed
|
||||||
|
ko=$(which konsole 2>/dev/null)
|
||||||
|
if [ -z $ko ];then ko="0";else ko="1";fi
|
||||||
|
}
|
||||||
|
chk_xt(){
|
||||||
|
# Check if xterm is installed
|
||||||
|
xt=$(which xterm 2>/dev/null)
|
||||||
|
if [ -z $xt ];then xt="0";else xt="1";fi
|
||||||
|
}
|
||||||
|
# Check for and set terminal
|
||||||
|
chk_xe
|
||||||
|
if [ $xe = "1" ];then
|
||||||
|
term=$(which x-terminal-emulator 2>/dev/null)
|
||||||
|
printf "Using X-Terminal-Emulator!\n"
|
||||||
|
else
|
||||||
|
chk_gt
|
||||||
|
fi
|
||||||
|
if [ $gt = "1" ];then
|
||||||
|
term=$(which gnome-terminal 2>/dev/null)
|
||||||
|
printf "Using Gnome-Terminal!\n"
|
||||||
|
elif [ $xe = "0" ]&&[ $gt = "0" ];then
|
||||||
|
chk_xt
|
||||||
|
fi
|
||||||
|
if [ $xt = "1" ];then
|
||||||
|
term=$(which xterm 2>/dev/null)
|
||||||
|
printf "Using XTerm!\n"
|
||||||
|
elif [ $xe = "0" ]&&[ $gt = "0" ]&&[ $xt = "0" ];then
|
||||||
|
chk_ko
|
||||||
|
fi
|
||||||
|
if [ $ko = "1" ];then
|
||||||
|
term=$(which konsole 2>/dev/null)
|
||||||
|
printf "Using Konsole!\n"
|
||||||
|
fi
|
||||||
|
# Bail if no terminal found
|
||||||
|
if [ "$ko" -eq "0" ]&&[ "$gt" -eq "0" ]&&[ "$xt" -eq "0" ]&&[ "$xe" -eq "0" ];then printf "No known terminals available!\n";exit 1;fi
|
||||||
|
# Get current directory
|
||||||
|
wd=$(pwd)
|
||||||
|
# Set date/time
|
||||||
|
# dt=$(date +%F_%H%M-%S-%N) #with hyphens
|
||||||
|
dt=$(date +%Y%m%d_%H%M%S) #just an underscore between date and time
|
||||||
|
if [ ! -d "logs" ]; then
|
||||||
|
mkdir logs
|
||||||
|
fi
|
||||||
|
# set log file relative filepath
|
||||||
|
clog="$wd/logs/console_log_$dt.txt"
|
||||||
|
elog="$wd/logs/event_log_$dt.txt"
|
||||||
|
# create the log file now with touch
|
||||||
|
touch $clog
|
||||||
|
touch $elog
|
||||||
|
# open new terminal windows to watch live log files
|
||||||
|
if [ "$term" == "$(which konsole)" ]||[ "$term" == "$(which xterm)" ];then
|
||||||
|
$term -e "tail -n 40 -f $clog" 2>/dev/null
|
||||||
|
$term -e "tail -n 40 -f $elog" 2>/dev/null
|
||||||
|
else
|
||||||
|
$term --window -e "tail -n 40 -f $clog" 2>/dev/null
|
||||||
|
$term --window -e "tail -n 40 -f $elog" 2>/dev/null
|
||||||
|
fi
|
||||||
|
# start dsd-fme with options and log files
|
||||||
|
dsd-fme $opts -J $elog 2> $clog
|
||||||
|
echo -------------------------------------------------------------------------------
|
||||||
|
echo -------------------------------------------------------------------------------
|
||||||
|
echo For any errors, see: $clog
|
||||||
|
echo Forward $clog and
|
||||||
|
echo Options: \" $opts \"
|
||||||
|
echo to developer on Github or Radio Reference for troubleshooting.
|
||||||
|
echo -------------------------------------------------------------------------------
|
||||||
|
echo -------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Set pause to diplay above message
|
||||||
|
read -p "Press ENTER to continue... " x
|
||||||
|
|
||||||
@@ -17,9 +17,21 @@
|
|||||||
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
|
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
|
||||||
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
||||||
|
|
||||||
#EDACS/EDACS-EA Digital Only
|
#EDACS Standard Network Analog and Digital
|
||||||
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
#dsd-fme -fh -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
#dsd-fme -fh -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
|
||||||
|
#EDACS Standard Network Analog and Digital (with ESK)
|
||||||
|
#dsd-fme -fH -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
#dsd-fme -fH -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
|
||||||
|
#EDACS Extended Address Analog and Digital
|
||||||
|
#dsd-fme -fe -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
#dsd-fme -fe -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
|
||||||
|
#EDACS Extended Address Analog and Digital (with ESK)
|
||||||
|
#dsd-fme -fE -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
#dsd-fme -fE -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||||
|
|
||||||
#NXDN48 Type-C or Type-D Trunking with Channel Map
|
#NXDN48 Type-C or Type-D Trunking with Channel Map
|
||||||
#dsd-fme -fi -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
#dsd-fme -fi -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||||
|
|||||||
64
flake.lock
generated
Normal file
64
flake.lock
generated
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709336216,
|
||||||
|
"narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1711163522,
|
||||||
|
"narHash": "sha256-YN/Ciidm+A0fmJPWlHBGvVkcarYWSC+s3NTPk/P+q3c=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "44d0940ea560dee511026a53f0e2e2cde489b4d4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "lib",
|
||||||
|
"lastModified": 1709237383,
|
||||||
|
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "lib",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
18
flake.nix
Normal file
18
flake.nix
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
description = "Digital Speech Decoder - Florida Man Edition ";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs@{ flake-parts, ... }:
|
||||||
|
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||||
|
systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
|
||||||
|
perSystem = { config, pkgs, ... }: {
|
||||||
|
packages.default = config.packages.dsd-fme;
|
||||||
|
|
||||||
|
packages.dsd-fme = pkgs.callPackage ./package.nix { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,8 +7,6 @@
|
|||||||
*
|
*
|
||||||
* Code adapted from http://www.aqdi.com/golay.htm
|
* Code adapted from http://www.aqdi.com/golay.htm
|
||||||
*
|
*
|
||||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
|
||||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
/**
|
/**
|
||||||
* Code taken and adapted from www.eccpage.com/rs.c
|
* Code taken and adapted from www.eccpage.com/rs.c
|
||||||
* Credit goes to Mr Simon Rockliff.
|
* Credit goes to Mr Simon Rockliff.
|
||||||
*
|
|
||||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
|
||||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in
|
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in
|
||||||
|
|||||||
71
include/bp.h
Normal file
71
include/bp.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#ifndef BP_H
|
||||||
|
#define BP_H
|
||||||
|
|
||||||
|
static const uint16_t BPK[256] = {
|
||||||
|
//000
|
||||||
|
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
|
||||||
|
//008
|
||||||
|
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
|
||||||
|
//016
|
||||||
|
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
|
||||||
|
//024
|
||||||
|
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E,
|
||||||
|
//032
|
||||||
|
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
|
||||||
|
//040
|
||||||
|
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
|
||||||
|
//048
|
||||||
|
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
|
||||||
|
//056
|
||||||
|
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36,
|
||||||
|
//064
|
||||||
|
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
|
||||||
|
//072
|
||||||
|
0x614C, 0x7E4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
|
||||||
|
//080
|
||||||
|
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
|
||||||
|
//088
|
||||||
|
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57,
|
||||||
|
//096
|
||||||
|
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
|
||||||
|
//104
|
||||||
|
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
|
||||||
|
//112
|
||||||
|
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
|
||||||
|
//120
|
||||||
|
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F,
|
||||||
|
//128
|
||||||
|
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
|
||||||
|
//136
|
||||||
|
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
|
||||||
|
//144
|
||||||
|
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
|
||||||
|
//152
|
||||||
|
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897,
|
||||||
|
//160
|
||||||
|
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
|
||||||
|
//168
|
||||||
|
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
|
||||||
|
//176
|
||||||
|
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
|
||||||
|
//184
|
||||||
|
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF,
|
||||||
|
//192
|
||||||
|
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
|
||||||
|
//200
|
||||||
|
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
|
||||||
|
//208
|
||||||
|
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
|
||||||
|
//216
|
||||||
|
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3,
|
||||||
|
//224
|
||||||
|
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
|
||||||
|
//232
|
||||||
|
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
|
||||||
|
//240
|
||||||
|
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
|
||||||
|
//248
|
||||||
|
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
493
include/dsd.h
493
include/dsd.h
@@ -17,8 +17,8 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//defined by CMakeLists.txt -- Disable by using cmake -DCOLORS=OFF ..
|
//ANSII Color Characters in Terminal -- Disable by using cmake -DCOLORSLOGS=OFF ..
|
||||||
#ifdef PRETTY_COLORS
|
#ifdef PRETTY_COLORS_LOGS
|
||||||
#define KNRM "\x1B[0m"
|
#define KNRM "\x1B[0m"
|
||||||
#define KRED "\x1B[31m"
|
#define KRED "\x1B[31m"
|
||||||
#define KGRN "\x1B[32m"
|
#define KGRN "\x1B[32m"
|
||||||
@@ -59,10 +59,13 @@
|
|||||||
#include "p25p1_heuristics.h"
|
#include "p25p1_heuristics.h"
|
||||||
|
|
||||||
//OSS support
|
//OSS support
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
|
#endif
|
||||||
|
#include <pulse/pulseaudio.h> //PULSE AUDIO
|
||||||
#include <pulse/simple.h> //PULSE AUDIO
|
#include <pulse/simple.h> //PULSE AUDIO
|
||||||
#include <pulse/error.h> //PULSE AUDIO
|
#include <pulse/error.h> //PULSE AUDIO
|
||||||
|
#include <pulse/introspect.h> //PULSE AUDIO
|
||||||
|
|
||||||
#define SAMPLE_RATE_IN 48000 //48000
|
#define SAMPLE_RATE_IN 48000 //48000
|
||||||
#define SAMPLE_RATE_OUT 8000 //8000
|
#define SAMPLE_RATE_OUT 8000 //8000
|
||||||
@@ -86,6 +89,86 @@
|
|||||||
|
|
||||||
extern volatile uint8_t exitflag; //fix for issue #136
|
extern volatile uint8_t exitflag; //fix for issue #136
|
||||||
|
|
||||||
|
//event history (each item)
|
||||||
|
typedef struct {
|
||||||
|
uint8_t write; //if this event needs to be written to a log file
|
||||||
|
uint8_t color_pair; //this value corresponds to which color pair the line should be in ncurses
|
||||||
|
int8_t systype; //indentifier of which decoded system type this is from (P25, DMR, etc)
|
||||||
|
int8_t subtype; //subtype of systpe (VLC, TLC, PDU data, System Event, etc)
|
||||||
|
uint32_t sys_id1; //sys_id1 through 5 will be a hierarchy of system identifiers
|
||||||
|
uint32_t sys_id2; //for example, trunked P25 has WACN:SYS:CC:SITE_ID:RFSS_ID
|
||||||
|
uint32_t sys_id3; //conventional may only use NAC, RAN, or Color Codes
|
||||||
|
uint32_t sys_id4; //
|
||||||
|
uint32_t sys_id5; //
|
||||||
|
int8_t gi; //group or individual
|
||||||
|
uint8_t enc; //clear or encrypted
|
||||||
|
uint8_t enc_alg; //alg if encrypted
|
||||||
|
uint16_t enc_key; //enc key id value, if encrypted (not key value or key variable)
|
||||||
|
uint64_t mi; //mi, or iv base value from OTA if provided
|
||||||
|
uint16_t svc; //other relevant svc opts if applicable
|
||||||
|
uint32_t source_id; //source radio id or other source value
|
||||||
|
uint32_t target_id; //group or individual target, or destination value
|
||||||
|
char src_str[200]; //source, expressed as a string for M17, YSF, DSTAR, dPMR
|
||||||
|
char tgt_str[200]; //target, expressed as a string for M17, YSF, DSTAR, dPMR
|
||||||
|
char t_name[200]; //this is the string present from any csv groupName import
|
||||||
|
char s_name[200]; //same as above, but if loaded from a src value and not tg value
|
||||||
|
char t_mode[200]; //mode, or A,B,D,DE from csv group import file
|
||||||
|
char s_mode[200]; //mode, or A,B,D,DE from csv group import file
|
||||||
|
uint32_t channel; //if this occurs on a trunking channel, which channel
|
||||||
|
time_t event_time; //time event occurred
|
||||||
|
|
||||||
|
uint8_t pdu[128*24]; //relevant link control, or full PDU if data call (in bytes)
|
||||||
|
char sysid_string[200]; //string comprised of system unique identifiers
|
||||||
|
char alias[2000]; //if this event has a source radio talker alias or similar
|
||||||
|
char gps_s[2000]; //gps, if returned, expressed as a string
|
||||||
|
char text_message[2000]; //if this event is a decoded text message, then it goes here
|
||||||
|
char event_string[2000]; //user legible and printable string for the event that happened
|
||||||
|
char internal_str[2000]; //string that relates to a DSD-FME generated event (ENC LO, error notices, etc)
|
||||||
|
} Event_History;
|
||||||
|
|
||||||
|
//event history for number of each items above
|
||||||
|
typedef struct {
|
||||||
|
Event_History Event_History_Items[255];
|
||||||
|
} Event_History_I;
|
||||||
|
|
||||||
|
//new audio filter stuff from: https://github.com/NedSimao/FilteringLibrary
|
||||||
|
typedef struct {
|
||||||
|
float coef[2];
|
||||||
|
float v_out[2];
|
||||||
|
}LPFilter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float coef;
|
||||||
|
float v_out[2];
|
||||||
|
float v_in[2];
|
||||||
|
|
||||||
|
}HPFilter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LPFilter lpf;
|
||||||
|
HPFilter hpf;
|
||||||
|
float out_in;
|
||||||
|
}PBFilter;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float alpha;
|
||||||
|
float beta;
|
||||||
|
|
||||||
|
float vin[3];
|
||||||
|
float vout[3];
|
||||||
|
|
||||||
|
}NOTCHFilter;
|
||||||
|
//end new filters
|
||||||
|
|
||||||
|
// Field list is here: http://0pointer.de/lennart/projects/pulseaudio/doxygen/structpa__sink__info.html
|
||||||
|
typedef struct pa_devicelist
|
||||||
|
{
|
||||||
|
uint8_t initialized;
|
||||||
|
char name[512];
|
||||||
|
uint32_t index;
|
||||||
|
char description[256];
|
||||||
|
} pa_devicelist_t;
|
||||||
|
|
||||||
//group csv import struct
|
//group csv import struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -229,16 +312,21 @@ typedef struct
|
|||||||
FILE *mbe_out_f;
|
FILE *mbe_out_f;
|
||||||
FILE *mbe_out_fR; //second slot on a TDMA system
|
FILE *mbe_out_fR; //second slot on a TDMA system
|
||||||
FILE *symbol_out_f;
|
FILE *symbol_out_f;
|
||||||
|
time_t symbol_out_file_creation_time; //time the symbol out file was created
|
||||||
|
uint8_t symbol_out_file_is_auto; //if the user hit the R key
|
||||||
float audio_gain;
|
float audio_gain;
|
||||||
float audio_gainR;
|
float audio_gainR;
|
||||||
|
float audio_gainA;
|
||||||
int audio_out;
|
int audio_out;
|
||||||
int dmr_stereo_wav;
|
int dmr_stereo_wav; //per-call wav file use (rename later)
|
||||||
|
int static_wav_file; //single static wav file for decoding duration
|
||||||
char wav_out_dir[512];
|
char wav_out_dir[512];
|
||||||
char wav_out_file[1024];
|
char wav_out_file[1024];
|
||||||
char wav_out_fileR[1024];
|
char wav_out_fileR[1024];
|
||||||
char wav_out_file_raw[1024];
|
char wav_out_file_raw[1024];
|
||||||
char symbol_out_file[1024];
|
char symbol_out_file[1024];
|
||||||
char lrrp_out_file[1024];
|
char lrrp_out_file[1024];
|
||||||
|
char event_out_file[1024];
|
||||||
char szNumbers[1024]; //**tera 10/32/64 char str
|
char szNumbers[1024]; //**tera 10/32/64 char str
|
||||||
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
|
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
|
||||||
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
|
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
|
||||||
@@ -282,6 +370,7 @@ typedef struct
|
|||||||
int rtl_started;
|
int rtl_started;
|
||||||
long int rtl_rms;
|
long int rtl_rms;
|
||||||
int monitor_input_audio;
|
int monitor_input_audio;
|
||||||
|
int analog_only;
|
||||||
int pulse_raw_rate_in;
|
int pulse_raw_rate_in;
|
||||||
int pulse_raw_rate_out;
|
int pulse_raw_rate_out;
|
||||||
int pulse_digi_rate_in;
|
int pulse_digi_rate_in;
|
||||||
@@ -296,9 +385,11 @@ typedef struct
|
|||||||
pa_simple *pulse_digi_dev_in;
|
pa_simple *pulse_digi_dev_in;
|
||||||
pa_simple *pulse_digi_dev_out;
|
pa_simple *pulse_digi_dev_out;
|
||||||
pa_simple *pulse_digi_dev_outR;
|
pa_simple *pulse_digi_dev_outR;
|
||||||
int use_ncurses_terminal;
|
char pa_input_idx[100];
|
||||||
int ncurses_compact;
|
char pa_output_idx[100];
|
||||||
int ncurses_history;
|
uint8_t use_ncurses_terminal;
|
||||||
|
uint8_t ncurses_compact;
|
||||||
|
uint8_t ncurses_history;
|
||||||
int reset_state;
|
int reset_state;
|
||||||
int payload;
|
int payload;
|
||||||
char output_name[1024];
|
char output_name[1024];
|
||||||
@@ -320,7 +411,6 @@ typedef struct
|
|||||||
short int aggressive_framesync;
|
short int aggressive_framesync;
|
||||||
|
|
||||||
int frame_m17;
|
int frame_m17;
|
||||||
int inverted_m17;
|
|
||||||
|
|
||||||
FILE *symbolfile;
|
FILE *symbolfile;
|
||||||
int call_alert;
|
int call_alert;
|
||||||
@@ -332,7 +422,8 @@ typedef struct
|
|||||||
char rigctlhostname[1024];
|
char rigctlhostname[1024];
|
||||||
|
|
||||||
//UDP Socket Blaster Audio
|
//UDP Socket Blaster Audio
|
||||||
int udp_sockfd;
|
int udp_sockfd; //digital
|
||||||
|
int udp_sockfdA; //analog 48k1
|
||||||
int udp_portno;
|
int udp_portno;
|
||||||
char udp_hostname[1024];
|
char udp_hostname[1024];
|
||||||
|
|
||||||
@@ -395,6 +486,12 @@ typedef struct
|
|||||||
int slot1_on;
|
int slot1_on;
|
||||||
int slot2_on;
|
int slot2_on;
|
||||||
|
|
||||||
|
//enable filter options
|
||||||
|
int use_lpf;
|
||||||
|
int use_hpf;
|
||||||
|
int use_pbf;
|
||||||
|
int use_hpf_d;
|
||||||
|
|
||||||
//'DSP' Format Output
|
//'DSP' Format Output
|
||||||
uint8_t use_dsp_output;
|
uint8_t use_dsp_output;
|
||||||
char dsp_out_file[2048];
|
char dsp_out_file[2048];
|
||||||
@@ -437,8 +534,8 @@ typedef struct
|
|||||||
//new stereo short sample storage
|
//new stereo short sample storage
|
||||||
short s_l[160]; //single sample left
|
short s_l[160]; //single sample left
|
||||||
short s_r[160]; //single sample right
|
short s_r[160]; //single sample right
|
||||||
short s_l4[4][160]; //quad sample for up to a P25p2 4V
|
short s_l4[18][160]; //quad sample for up to a P25p2 4V
|
||||||
short s_r4[4][160]; //quad sample for up to a P25p2 4V
|
short s_r4[18][160]; //quad sample for up to a P25p2 4V
|
||||||
//new stereo short sample storage tapped from 48_k internal upsampling
|
//new stereo short sample storage tapped from 48_k internal upsampling
|
||||||
short s_lu[160*6]; //single sample left
|
short s_lu[160*6]; //single sample left
|
||||||
short s_ru[160*6]; //single sample right
|
short s_ru[160*6]; //single sample right
|
||||||
@@ -485,6 +582,9 @@ typedef struct
|
|||||||
int lasttgR;
|
int lasttgR;
|
||||||
int lastsrc;
|
int lastsrc;
|
||||||
int lastsrcR;
|
int lastsrcR;
|
||||||
|
int8_t gi[2]; //group, or private call, per slot
|
||||||
|
uint8_t eh_index;
|
||||||
|
uint8_t eh_slot;
|
||||||
int nac;
|
int nac;
|
||||||
int errs;
|
int errs;
|
||||||
int errs2;
|
int errs2;
|
||||||
@@ -497,6 +597,7 @@ typedef struct
|
|||||||
char slot0light[8];
|
char slot0light[8];
|
||||||
float aout_gain;
|
float aout_gain;
|
||||||
float aout_gainR;
|
float aout_gainR;
|
||||||
|
float aout_gainA;
|
||||||
float aout_max_buf[200];
|
float aout_max_buf[200];
|
||||||
float aout_max_bufR[200];
|
float aout_max_bufR[200];
|
||||||
float *aout_max_buf_p;
|
float *aout_max_buf_p;
|
||||||
@@ -522,8 +623,8 @@ typedef struct
|
|||||||
int payload_keyidR;
|
int payload_keyidR;
|
||||||
int payload_mfid;
|
int payload_mfid;
|
||||||
int payload_mfidR;
|
int payload_mfidR;
|
||||||
int payload_mi;
|
unsigned long long int payload_mi;
|
||||||
int payload_miR;
|
unsigned long long int payload_miR;
|
||||||
unsigned long long int payload_miN;
|
unsigned long long int payload_miN;
|
||||||
unsigned long long int payload_miP;
|
unsigned long long int payload_miP;
|
||||||
int p25vc;
|
int p25vc;
|
||||||
@@ -532,13 +633,24 @@ typedef struct
|
|||||||
unsigned long long int K2;
|
unsigned long long int K2;
|
||||||
unsigned long long int K3;
|
unsigned long long int K3;
|
||||||
unsigned long long int K4;
|
unsigned long long int K4;
|
||||||
int M;
|
uint8_t forced_alg_id;
|
||||||
int menuopen;
|
int menuopen;
|
||||||
|
|
||||||
|
//AES Key Segments
|
||||||
|
unsigned long long int A1[2];
|
||||||
|
unsigned long long int A2[2];
|
||||||
|
unsigned long long int A3[2];
|
||||||
|
unsigned long long int A4[2];
|
||||||
|
int aes_key_loaded[2];
|
||||||
|
|
||||||
|
//xl specific, we need to know if the ESS is from HDU, or from LDU2
|
||||||
|
int xl_is_hdu;
|
||||||
|
|
||||||
unsigned int debug_audio_errors;
|
unsigned int debug_audio_errors;
|
||||||
unsigned int debug_audio_errorsR;
|
unsigned int debug_audio_errorsR;
|
||||||
unsigned int debug_header_errors;
|
unsigned int debug_header_errors;
|
||||||
unsigned int debug_header_critical_errors;
|
unsigned int debug_header_critical_errors;
|
||||||
|
int debug_mode; //debug misc things
|
||||||
|
|
||||||
// Last dibit read
|
// Last dibit read
|
||||||
int last_dibit;
|
int last_dibit;
|
||||||
@@ -554,6 +666,7 @@ typedef struct
|
|||||||
short pulse_raw_out_buffer; //HERE HERE
|
short pulse_raw_out_buffer; //HERE HERE
|
||||||
|
|
||||||
unsigned int dmr_color_code;
|
unsigned int dmr_color_code;
|
||||||
|
unsigned int dmr_t3_syscode;
|
||||||
unsigned int nxdn_last_ran;
|
unsigned int nxdn_last_ran;
|
||||||
unsigned int nxdn_last_rid;
|
unsigned int nxdn_last_rid;
|
||||||
unsigned int nxdn_last_tg;
|
unsigned int nxdn_last_tg;
|
||||||
@@ -562,6 +675,7 @@ typedef struct
|
|||||||
char nxdn_call_type[1024];
|
char nxdn_call_type[1024];
|
||||||
|
|
||||||
unsigned long long int dmr_lrrp_source[2];
|
unsigned long long int dmr_lrrp_source[2];
|
||||||
|
unsigned long long int dmr_lrrp_target[2];
|
||||||
|
|
||||||
NxdnElementsContent_t NxdnElementsContent;
|
NxdnElementsContent_t NxdnElementsContent;
|
||||||
|
|
||||||
@@ -598,6 +712,9 @@ typedef struct
|
|||||||
|
|
||||||
//new stuff below here
|
//new stuff below here
|
||||||
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
|
||||||
|
uint8_t data_block_poc[2]; //padding octets in the header (needed for Data PDU Decryption)
|
||||||
|
uint16_t data_byte_ctr[2]; //number of bytes acculumated
|
||||||
|
uint8_t data_ks_start[2]; //where the start of the keystream should be applied to PDU data
|
||||||
uint8_t dmr_pdu_sf[2][24*128]; //unified pdu 'superframe' //[slot][byte] -- increased capacity to 127(+1) full rate blocks
|
uint8_t dmr_pdu_sf[2][24*128]; //unified pdu 'superframe' //[slot][byte] -- increased capacity to 127(+1) full rate blocks
|
||||||
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
|
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
|
||||||
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
|
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
|
||||||
@@ -609,24 +726,39 @@ typedef struct
|
|||||||
|
|
||||||
//dmr talker alias new/fixed stuff
|
//dmr talker alias new/fixed stuff
|
||||||
uint8_t dmr_alias_format[2]; //per slot
|
uint8_t dmr_alias_format[2]; //per slot
|
||||||
uint8_t dmr_alias_len[2]; //per slot
|
uint8_t dmr_alias_block_len[2]; //per slot
|
||||||
|
uint8_t dmr_alias_char_size[2]; //per slot
|
||||||
char dmr_alias_block_segment[2][4][7][16]; //2 slots, by 4 blocks, by up to 7 alias bytes that are up to 16-bit chars
|
char dmr_alias_block_segment[2][4][7][16]; //2 slots, by 4 blocks, by up to 7 alias bytes that are up to 16-bit chars
|
||||||
char dmr_embedded_gps[2][200]; //2 slots by 99 char string for string embedded gps
|
char dmr_embedded_gps[2][600]; //2 slots by 99 char string for string embedded gps
|
||||||
char dmr_lrrp_gps[2][200]; //2 slots by 99 char string for string lrrp gps
|
char dmr_lrrp_gps[2][600]; //2 slots by 99 char string for string lrrp gps
|
||||||
char dmr_site_parms[200]; //string for site/net info depending on type of DMR system (TIII or Con+)
|
char dmr_site_parms[200]; //string for site/net info depending on type of DMR system (TIII or Con+)
|
||||||
char call_string[2][200]; //string for call information
|
char call_string[2][200]; //string for call information
|
||||||
char active_channel[31][200]; //string for storing and displaying active trunking channels
|
char active_channel[31][200]; //string for storing and displaying active trunking channels
|
||||||
|
|
||||||
|
//Generic Talker Alias String
|
||||||
|
char generic_talker_alias[2][500];
|
||||||
|
|
||||||
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
||||||
|
|
||||||
|
//event history itemized per slot
|
||||||
|
Event_History_I * event_history_s;
|
||||||
|
|
||||||
|
//new audio filter structs
|
||||||
|
LPFilter RCFilter;
|
||||||
|
HPFilter HRCFilter;
|
||||||
|
PBFilter PBF;
|
||||||
|
NOTCHFilter NF;
|
||||||
|
LPFilter RCFilterL;
|
||||||
|
HPFilter HRCFilterL;
|
||||||
|
LPFilter RCFilterR;
|
||||||
|
HPFilter HRCFilterR;
|
||||||
|
|
||||||
char dpmr_caller_id[20];
|
char dpmr_caller_id[20];
|
||||||
char dpmr_target_id[20];
|
char dpmr_target_id[20];
|
||||||
|
|
||||||
int dpmr_color_code;
|
int dpmr_color_code;
|
||||||
|
|
||||||
short int dmr_stereo; //need state variable for upsample function
|
short int dmr_stereo; //need state variable for upsample function
|
||||||
short int dmr_ms_rc;
|
|
||||||
short int dmr_ms_mode;
|
short int dmr_ms_mode;
|
||||||
unsigned int dmrburstL;
|
unsigned int dmrburstL;
|
||||||
unsigned int dmrburstR;
|
unsigned int dmrburstR;
|
||||||
@@ -640,6 +772,23 @@ typedef struct
|
|||||||
int DMRvcL;
|
int DMRvcL;
|
||||||
int DMRvcR;
|
int DMRvcR;
|
||||||
|
|
||||||
|
//keystream octet and bit arrays
|
||||||
|
uint8_t ks_octetL[129*18]; //arbitary size, but large enough for the largest packed PDUs
|
||||||
|
uint8_t ks_octetR[129*18]; //arbitary size, but large enough for the largest packed PDUs
|
||||||
|
uint8_t ks_bitstreamL[128*18*8]; //arbitary size, but large enough for the largest PDUs
|
||||||
|
uint8_t ks_bitstreamR[129*18*8]; //arbitary size, but large enough for the largest PDUs
|
||||||
|
int octet_counter;
|
||||||
|
long int bit_counterL;
|
||||||
|
long int bit_counterR;
|
||||||
|
|
||||||
|
//AES Specific Variables
|
||||||
|
uint8_t aes_key[32]; //was 64 for some reason
|
||||||
|
uint8_t aes_iv[16];
|
||||||
|
uint8_t aes_ivR[16];
|
||||||
|
|
||||||
|
//NXDN DES and AES, signal new VCALL_IV and new IV
|
||||||
|
uint8_t nxdn_new_iv; //1 when a new IV comes in, else 0
|
||||||
|
|
||||||
short int dmr_encL;
|
short int dmr_encL;
|
||||||
short int dmr_encR;
|
short int dmr_encR;
|
||||||
|
|
||||||
@@ -654,6 +803,7 @@ typedef struct
|
|||||||
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
||||||
int ess_b[2][96]; //external storage for ESS_B fragments
|
int ess_b[2][96]; //external storage for ESS_B fragments
|
||||||
int fourv_counter[2]; //external reference counter for ESS_B fragment collection
|
int fourv_counter[2]; //external reference counter for ESS_B fragment collection
|
||||||
|
int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe
|
||||||
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
||||||
|
|
||||||
//iden freq storage for frequency calculations
|
//iden freq storage for frequency calculations
|
||||||
@@ -685,13 +835,36 @@ typedef struct
|
|||||||
|
|
||||||
//edacs
|
//edacs
|
||||||
int ea_mode;
|
int ea_mode;
|
||||||
int esk_mode;
|
|
||||||
unsigned short esk_mask;
|
unsigned short esk_mask;
|
||||||
unsigned long long int edacs_site_id;
|
unsigned long long int edacs_site_id;
|
||||||
|
uint32_t edacs_sys_id;
|
||||||
|
uint32_t edacs_area_code;
|
||||||
int edacs_lcn_count; //running tally of lcn's observed on edacs system
|
int edacs_lcn_count; //running tally of lcn's observed on edacs system
|
||||||
int edacs_cc_lcn; //current lcn for the edacs control channel
|
int edacs_cc_lcn; //current lcn for the edacs control channel
|
||||||
int edacs_vc_lcn; //current lcn for any active vc (not the one we are tuned/tuning to)
|
int edacs_vc_lcn; //current lcn for any active vc (not the one we are tuned/tuning to)
|
||||||
int edacs_tuned_lcn; //the vc we are currently tuned to...above variable is for updating all in the matrix
|
int edacs_tuned_lcn; //the vc we are currently tuned to...above variable is for updating all in the matrix
|
||||||
|
int edacs_vc_call_type; //the type of call on the given VC - see defines below
|
||||||
|
int edacs_a_bits; // Agency Significant Bits
|
||||||
|
int edacs_f_bits; // Fleet Significant Bits
|
||||||
|
int edacs_s_bits; //Subfleet Significant Bits
|
||||||
|
int edacs_a_shift; //Calculated Shift for A Bits
|
||||||
|
int edacs_f_shift; //Calculated Shift for F Bits
|
||||||
|
int edacs_a_mask; //Calculated Mask for A Bits
|
||||||
|
int edacs_f_mask; //Calculated Mask for F Bits
|
||||||
|
int edacs_s_mask; //Calculated Mask for S Bits
|
||||||
|
|
||||||
|
//flags for EDACS call type
|
||||||
|
#define EDACS_IS_VOICE 0x01
|
||||||
|
#define EDACS_IS_DIGITAL 0x02
|
||||||
|
#define EDACS_IS_EMERGENCY 0x04
|
||||||
|
#define EDACS_IS_GROUP 0x08
|
||||||
|
#define EDACS_IS_INDIVIDUAL 0x10
|
||||||
|
#define EDACS_IS_ALL_CALL 0x20
|
||||||
|
#define EDACS_IS_INTERCONNECT 0x40
|
||||||
|
#define EDACS_IS_TEST_CALL 0x80
|
||||||
|
#define EDACS_IS_AGENCY_CALL 0x100
|
||||||
|
#define EDACS_IS_FLEET_CALL 0x200
|
||||||
|
|
||||||
//trunking group and lcn freq list
|
//trunking group and lcn freq list
|
||||||
long int trunk_lcn_freq[26]; //max number on an EDACS system, should be enough on DMR too hopefully
|
long int trunk_lcn_freq[26]; //max number on an EDACS system, should be enough on DMR too hopefully
|
||||||
@@ -703,6 +876,7 @@ typedef struct
|
|||||||
time_t last_cc_sync_time; //use this to start hunting for CC after signal lost
|
time_t last_cc_sync_time; //use this to start hunting for CC after signal lost
|
||||||
time_t last_vc_sync_time; //flag for voice activity bursts, tune back on con+ after more than x seconds no voice
|
time_t last_vc_sync_time; //flag for voice activity bursts, tune back on con+ after more than x seconds no voice
|
||||||
time_t last_active_time; //time the a 'call grant' was received, used to clear the active_channel strings after x seconds
|
time_t last_active_time; //time the a 'call grant' was received, used to clear the active_channel strings after x seconds
|
||||||
|
time_t last_t3_tune_time; //last time a DMR T3 grant was received, this is used to prevent a rogue p_clear condition from immediately sending back to CC
|
||||||
int is_con_plus; //con_plus flag for knowing its safe to skip payload channel after x seconds of no voice sync
|
int is_con_plus; //con_plus flag for knowing its safe to skip payload channel after x seconds of no voice sync
|
||||||
|
|
||||||
//new nxdn stuff
|
//new nxdn stuff
|
||||||
@@ -714,6 +888,7 @@ typedef struct
|
|||||||
uint8_t nxdn_sacch_frame_segcrc[4];
|
uint8_t nxdn_sacch_frame_segcrc[4];
|
||||||
uint8_t nxdn_alias_block_number;
|
uint8_t nxdn_alias_block_number;
|
||||||
char nxdn_alias_block_segment[4][4][8];
|
char nxdn_alias_block_segment[4][4][8];
|
||||||
|
uint16_t nxdn_pn95_seed;
|
||||||
|
|
||||||
//site/srv/cch info
|
//site/srv/cch info
|
||||||
char nxdn_location_category[14];
|
char nxdn_location_category[14];
|
||||||
@@ -727,11 +902,11 @@ typedef struct
|
|||||||
uint8_t nxdn_bw;
|
uint8_t nxdn_bw;
|
||||||
|
|
||||||
//multi-key array
|
//multi-key array
|
||||||
unsigned long long int rkey_array[0xFFFF];
|
unsigned long long int rkey_array[0x1FFFF];
|
||||||
int keyloader; //let us know the keyloader is active
|
int keyloader; //let us know the keyloader is active
|
||||||
|
|
||||||
//dmr late entry mi
|
//dmr late entry mi
|
||||||
uint64_t late_entry_mi_fragment[2][7][3];
|
uint64_t late_entry_mi_fragment[2][8][3];
|
||||||
|
|
||||||
//dmr manufacturer branding and sub_branding (i.e., Motorola and Con+)
|
//dmr manufacturer branding and sub_branding (i.e., Motorola and Con+)
|
||||||
char dmr_branding[20];
|
char dmr_branding[20];
|
||||||
@@ -740,8 +915,8 @@ typedef struct
|
|||||||
//Remus DMR End Call Alert Beep
|
//Remus DMR End Call Alert Beep
|
||||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||||
|
|
||||||
//Upsampled Audio Smoothing
|
//Bitmap Filtering Options
|
||||||
uint8_t audio_smoothing;
|
int audio_smoothing;
|
||||||
|
|
||||||
//YSF Fusion Call Strings and Info
|
//YSF Fusion Call Strings and Info
|
||||||
uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc.
|
uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc.
|
||||||
@@ -767,11 +942,12 @@ typedef struct
|
|||||||
|
|
||||||
//M17 Storage
|
//M17 Storage
|
||||||
uint8_t m17_lsf[360];
|
uint8_t m17_lsf[360];
|
||||||
|
uint8_t m17_pkt[850];
|
||||||
uint8_t m17_str_dt; //stream contents
|
uint8_t m17_str_dt; //stream contents
|
||||||
|
|
||||||
unsigned long long int m17_dst;
|
unsigned long long int m17_dst;
|
||||||
unsigned long long int m17_src;
|
unsigned long long int m17_src;
|
||||||
uint8_t m17_can;
|
uint8_t m17_can; //can value that was decoded from signal
|
||||||
|
|
||||||
char m17_dst_csd[20];
|
char m17_dst_csd[20];
|
||||||
char m17_src_csd[20];
|
char m17_src_csd[20];
|
||||||
@@ -779,13 +955,22 @@ typedef struct
|
|||||||
char m17_src_str[50];
|
char m17_src_str[50];
|
||||||
char m17_dst_str[50];
|
char m17_dst_str[50];
|
||||||
|
|
||||||
uint8_t m17_meta[16]; //packed meta
|
uint8_t m17_meta[16]; //packed meta
|
||||||
uint8_t m17_enc; //enc type
|
uint8_t m17_aes_iv[16]; //aes iv
|
||||||
uint8_t m17_enc_st; //scrambler or data subtye
|
uint8_t m17_enc; //enc type
|
||||||
|
uint8_t m17_enc_st; //scrambler or data subtye
|
||||||
|
|
||||||
|
char m17_text_string[1024];
|
||||||
|
char m17_gnss_string[1024];
|
||||||
|
char m17_data_string[1024];
|
||||||
|
char m17_meta_string[1024];
|
||||||
|
|
||||||
|
float m17_viterbi_err;
|
||||||
|
|
||||||
//misc str storage
|
//misc str storage
|
||||||
char str50a[50];
|
char str50a[50];
|
||||||
char str50b[50];
|
char str50b[50];
|
||||||
|
char str50c[50];
|
||||||
|
|
||||||
//Codec2
|
//Codec2
|
||||||
#ifdef USE_CODEC2
|
#ifdef USE_CODEC2
|
||||||
@@ -793,22 +978,42 @@ typedef struct
|
|||||||
struct CODEC2 *codec2_1600; //M17 halfrate
|
struct CODEC2 *codec2_1600; //M17 halfrate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//tyt_ap=1 active
|
||||||
|
int tyt_ap;
|
||||||
|
int tyt_bp;
|
||||||
|
int tyt_ep;
|
||||||
|
// retrevis rc2
|
||||||
|
int retevis_ap;
|
||||||
|
void *rc2_context;
|
||||||
|
|
||||||
|
//kenwood scrambler on DMR with forced application
|
||||||
|
int ken_sc;
|
||||||
|
|
||||||
|
//anytone bp
|
||||||
|
int any_bp;
|
||||||
|
|
||||||
|
//baofeng ap
|
||||||
|
int baofeng_ap;
|
||||||
|
|
||||||
|
//connect systems ee
|
||||||
|
int csi_ee;
|
||||||
|
|
||||||
|
//generic ks
|
||||||
|
int straight_ks;
|
||||||
|
int straight_mod;
|
||||||
|
|
||||||
|
uint8_t static_ks_bits[2][882];
|
||||||
|
int static_ks_counter[2];
|
||||||
|
|
||||||
} dsd_state;
|
} dsd_state;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Frame sync patterns
|
* Frame sync patterns
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//The inverse of LSF also seems to be Stream Frame Type, only going to work on Stream mode for now
|
//M17 Sync Patterns
|
||||||
#define M17_LSF "11113313"
|
#define M17_LSF "11113313"
|
||||||
#define M17_STR "33331131"
|
#define M17_STR "33331131"
|
||||||
//alternating with last symbol opposite of first symbol of LSF
|
|
||||||
#define M17_PRE "31313131"
|
|
||||||
#define M17_PIV "13131313"
|
|
||||||
#define M17_PRE_LSF "3131313133331131" //Preamble + LSF
|
|
||||||
#define M17_PIV_LSF "1313131311113313" //Preamble + LSF
|
|
||||||
// #define M17_BRT "31331111"
|
|
||||||
// #define M17_PKT "13113333"
|
|
||||||
|
|
||||||
#define FUSION_SYNC "31111311313113131131"
|
#define FUSION_SYNC "31111311313113131131"
|
||||||
#define INV_FUSION_SYNC "13333133131331313313"
|
#define INV_FUSION_SYNC "13333133131331313313"
|
||||||
@@ -850,7 +1055,7 @@ typedef struct
|
|||||||
#define NXDN_PANDFSW "3131133313131331131" //19 symbols
|
#define NXDN_PANDFSW "3131133313131331131" //19 symbols
|
||||||
#define INV_NXDN_PANDFSW "1313311131313113313" //19 symbols
|
#define INV_NXDN_PANDFSW "1313311131313113313" //19 symbols
|
||||||
|
|
||||||
#define DMR_RC_DATA_SYNC "131331111133133133311313"
|
#define DMR_RESERVED_SYNC "131331111133133133311313"
|
||||||
|
|
||||||
#define DMR_DIRECT_MODE_TS1_DATA_SYNC "331333313111313133311111"
|
#define DMR_DIRECT_MODE_TS1_DATA_SYNC "331333313111313133311111"
|
||||||
#define DMR_DIRECT_MODE_TS1_VOICE_SYNC "113111131333131311133333"
|
#define DMR_DIRECT_MODE_TS1_VOICE_SYNC "113111131333131311133333"
|
||||||
@@ -914,6 +1119,7 @@ void closePulseInput (dsd_opts * opts);
|
|||||||
void closePulseOutput (dsd_opts * opts);
|
void closePulseOutput (dsd_opts * opts);
|
||||||
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||||
void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state);
|
void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state);
|
||||||
|
void writeSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state); //short mono to stereo wav file
|
||||||
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); //short mono output slot 1
|
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); //short mono output slot 1
|
||||||
void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); //short mono output slot 2
|
void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); //short mono output slot 2
|
||||||
//new float stuff
|
//new float stuff
|
||||||
@@ -922,15 +1128,32 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state); //float stere
|
|||||||
void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2
|
void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2
|
||||||
void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state); //float mono
|
void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state); //float mono
|
||||||
void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //float gain control
|
void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //float gain control
|
||||||
|
void agsm (dsd_opts * opts, dsd_state * state, short * input, int len); //short gain control for analog things
|
||||||
|
void analog_gain (dsd_opts * opts, dsd_state * state, short * input, int len); //manual gain handling for analong things
|
||||||
//new short stuff
|
//new short stuff
|
||||||
|
void playSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state); //short mono mix
|
||||||
|
void playSynthesizedVoiceMSR (dsd_opts * opts, dsd_state * state); //short mono mix R (needed for OSS 48k input/output)
|
||||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
||||||
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
||||||
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
||||||
|
void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe
|
||||||
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
||||||
//
|
//
|
||||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
void openAudioOutDevice (dsd_opts * opts, int speed);
|
||||||
void openAudioInDevice (dsd_opts * opts);
|
void openAudioInDevice (dsd_opts * opts);
|
||||||
|
|
||||||
|
//pulse sources and sinks
|
||||||
|
void parse_pulse_input_string (dsd_opts * opts, char * input);
|
||||||
|
void parse_pulse_output_string (dsd_opts * opts, char * input);
|
||||||
|
void pa_state_cb (pa_context *c, void *userdata);
|
||||||
|
void pa_sinklist_cb (pa_context *c, const pa_sink_info *l, int eol, void *userdata);
|
||||||
|
void pa_sourcelist_cb (pa_context *c, const pa_source_info *l, int eol, void *userdata);
|
||||||
|
int pa_get_devicelist (pa_devicelist_t *input, pa_devicelist_t *output);
|
||||||
|
int pulse_list();
|
||||||
|
|
||||||
|
//parse a user string into a uint8_t array
|
||||||
|
uint16_t parse_raw_user_string (char * input, uint8_t * output);
|
||||||
|
|
||||||
int getDibit (dsd_opts * opts, dsd_state * state);
|
int getDibit (dsd_opts * opts, dsd_state * state);
|
||||||
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
|
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
|
||||||
int digitize (dsd_opts* opts, dsd_state* state, int symbol);
|
int digitize (dsd_opts* opts, dsd_state* state, int symbol);
|
||||||
@@ -943,6 +1166,11 @@ void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
|||||||
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||||
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||||
int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||||
|
void keyring(dsd_opts * opts, dsd_state * state);
|
||||||
|
void read_sdrtrunk_json_format (dsd_opts * opts, dsd_state * state);
|
||||||
|
void ambe2_codeword_print_f (dsd_opts * opts, char ambe_fr[4][24]);
|
||||||
|
void ambe2_codeword_print_b (dsd_opts * opts, char ambe_fr[4][24]);
|
||||||
|
void ambe2_codeword_print_i (dsd_opts * opts, char ambe_fr[4][24]);
|
||||||
void openMbeInFile (dsd_opts * opts, dsd_state * state);
|
void openMbeInFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
|
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
|
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
|
||||||
@@ -951,9 +1179,15 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
|
|||||||
void openWavOutFile (dsd_opts * opts, dsd_state * state);
|
void openWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void openWavOutFileL (dsd_opts * opts, dsd_state * state);
|
void openWavOutFileL (dsd_opts * opts, dsd_state * state);
|
||||||
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
|
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
|
||||||
|
void openWavOutFileLR (dsd_opts * opts, dsd_state * state); //stereo wav file for tdma decoded speech
|
||||||
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
|
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state);
|
||||||
|
SNDFILE * open_wav_file (char * dir, char * temp_filename, uint16_t sample_rate, uint8_t ext);
|
||||||
|
SNDFILE * close_wav_file(SNDFILE * wav_file);
|
||||||
|
SNDFILE * close_and_rename_wav_file(SNDFILE * wav_file, char * wav_out_filename, char * dir, Event_History_I * event_struct);
|
||||||
|
SNDFILE * close_and_delete_wav_file(SNDFILE * wav_file, char * wav_out_filename);
|
||||||
void openSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
void openSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
|
void rotate_symbol_out_file (dsd_opts * opts, dsd_state * state);
|
||||||
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample);
|
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample);
|
||||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state);
|
void closeWavOutFileL (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1003,7 +1237,6 @@ void processDSTAR_HD (dsd_opts * opts, dsd_state * state); //DSTAR Header
|
|||||||
void processDSTAR_SD (dsd_opts * opts, dsd_state * state, uint8_t * sd); //DSTAR Slow Data
|
void processDSTAR_SD (dsd_opts * opts, dsd_state * state, uint8_t * sd); //DSTAR Slow Data
|
||||||
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
||||||
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
||||||
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
|
||||||
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
||||||
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
|
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
|
||||||
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
|
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
|
||||||
@@ -1012,15 +1245,26 @@ short nxdn_filter(short sample);
|
|||||||
short dpmr_filter(short sample);
|
short dpmr_filter(short sample);
|
||||||
short m17_filter(short sample);
|
short m17_filter(short sample);
|
||||||
|
|
||||||
|
//utility functions
|
||||||
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
|
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
|
||||||
|
uint64_t convert_bits_into_output (uint8_t * input, int len);
|
||||||
|
void pack_bit_array_into_byte_array (uint8_t * input, uint8_t * output, int len);
|
||||||
|
void pack_bit_array_into_byte_array_asym (uint8_t * input, uint8_t * output, int len);
|
||||||
|
void unpack_byte_array_into_bit_array (uint8_t * input, uint8_t * output, int len);
|
||||||
|
|
||||||
|
//ambe pack and unpack functions
|
||||||
|
void pack_ambe (char * input, uint8_t * output, int len);
|
||||||
|
void unpack_ambe (uint8_t * input, char * ambe);
|
||||||
|
|
||||||
void ncursesOpen (dsd_opts * opts, dsd_state * state);
|
void ncursesOpen (dsd_opts * opts, dsd_state * state);
|
||||||
void ncursesPrinter (dsd_opts * opts, dsd_state * state);
|
void ncursesPrinter (dsd_opts * opts, dsd_state * state);
|
||||||
|
void ncursesMenu (dsd_opts * opts, dsd_state * state);
|
||||||
|
uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c);
|
||||||
void ncursesClose ();
|
void ncursesClose ();
|
||||||
|
|
||||||
//new NXDN Functions start here!
|
//new NXDN Functions start here!
|
||||||
void nxdn_frame (dsd_opts * opts, dsd_state * state);
|
void nxdn_frame (dsd_opts * opts, dsd_state * state);
|
||||||
void nxdn_descramble (uint8_t dibits[], int len);
|
void nxdn_pn95_dibit_scrambler(dsd_state * state, uint8_t * dibits, int len);
|
||||||
//nxdn deinterleaving/depuncturing functions
|
//nxdn deinterleaving/depuncturing functions
|
||||||
void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
|
||||||
void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
||||||
@@ -1029,7 +1273,10 @@ void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[3
|
|||||||
//type-d 'idas' deinterleaving/depuncturing functions
|
//type-d 'idas' deinterleaving/depuncturing functions
|
||||||
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
|
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
|
||||||
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
|
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
|
||||||
//end
|
//DCR Mode
|
||||||
|
void nxdn_deperm_sacch2(dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
|
||||||
|
void nxdn_deperm_pich_tch(dsd_opts * opts, dsd_state * state, uint8_t bits[144], uint8_t lich);
|
||||||
|
//MT and Voice
|
||||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
||||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
||||||
//Osmocom OP25 12 Rate Trellis Decoder (for NXDN, M17, YSF, etc)
|
//Osmocom OP25 12 Rate Trellis Decoder (for NXDN, M17, YSF, etc)
|
||||||
@@ -1050,6 +1297,20 @@ void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
|
|||||||
void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
|
void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
|
||||||
void CNXDNConvolution_init();
|
void CNXDNConvolution_init();
|
||||||
|
|
||||||
|
//libM17 viterbi decoder
|
||||||
|
|
||||||
|
//libm17 magic soft decision based viterbi
|
||||||
|
#define SYM_PER_PLD 184
|
||||||
|
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD]);
|
||||||
|
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2]);
|
||||||
|
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2]);
|
||||||
|
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len);
|
||||||
|
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len);
|
||||||
|
void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos);
|
||||||
|
uint32_t viterbi_chainback(uint8_t* out, size_t pos, uint16_t len);
|
||||||
|
void viterbi_reset(void);
|
||||||
|
uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2);
|
||||||
|
|
||||||
//keeping these
|
//keeping these
|
||||||
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
|
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
|
||||||
void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||||
@@ -1068,6 +1329,10 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message
|
|||||||
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||||
//Type-D SCCH Message Decoder
|
//Type-D SCCH Message Decoder
|
||||||
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
|
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
|
||||||
|
void NXDN_decode_VCALL_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||||
|
void NXDN_decode_ALIAS_ARIB(dsd_opts * opts, dsd_state * state, uint8_t * Message);
|
||||||
|
uint32_t sjis_char_to_unicode(uint16_t sjis);
|
||||||
|
int utf8_encode(int c, char *buf);
|
||||||
|
|
||||||
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||||
|
|
||||||
@@ -1093,7 +1358,7 @@ rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword);
|
|||||||
|
|
||||||
//DMR CRC Functions
|
//DMR CRC Functions
|
||||||
uint16_t ComputeCrcCCITT(uint8_t * DMRData);
|
uint16_t ComputeCrcCCITT(uint8_t * DMRData);
|
||||||
uint16_t ComputeCrcCCITT16d(const uint8_t buf[], uint8_t len);
|
uint16_t ComputeCrcCCITT16d(const uint8_t * buf, uint32_t len);
|
||||||
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask);
|
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask);
|
||||||
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
||||||
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
|
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
|
||||||
@@ -1103,23 +1368,36 @@ uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
|
|||||||
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
||||||
void dmr_data_sync (dsd_opts * opts, dsd_state * state);
|
void dmr_data_sync (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type);
|
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t * IrrecoverableErrors, uint8_t type);
|
||||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||||
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
||||||
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
||||||
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18]); //simplier trellis decoder
|
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18]); //simplier trellis decoder
|
||||||
void beeper (dsd_opts * opts, dsd_state * state, int lr); //the tone beeper function
|
void beeper (dsd_opts * opts, dsd_state * state, int lr, int id, int ad, int len);
|
||||||
void dmr_gateway_identifier (uint32_t source, uint32_t target); //translate special addresses
|
void dmr_gateway_identifier (uint32_t source, uint32_t target); //translate special addresses
|
||||||
|
|
||||||
//Embedded Alias and GPS reports
|
//Embedded Alias and GPS reports
|
||||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_talker_alias_lc_header (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_talker_alias_lc_blocks (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t block_num, uint8_t * lc_bits);
|
||||||
|
void dmr_talker_alias_lc_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t block_num, uint8_t char_size, uint16_t end);
|
||||||
|
void apx_embedded_alias_test_phase1 (dsd_opts * opts, dsd_state * state);
|
||||||
|
void apx_embedded_alias_header_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
|
void apx_embedded_alias_header_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
|
void apx_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
|
void apx_embedded_alias_blocks_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
|
void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t num_bits, uint8_t * input);
|
||||||
|
void apx_embedded_alias_dump (dsd_opts * opts, dsd_state * state, uint8_t slot, uint16_t num_bytes, uint8_t * input, uint8_t * decoded);
|
||||||
|
void l3h_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits);
|
||||||
|
void l3h_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input);
|
||||||
|
void tait_iso7_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input);
|
||||||
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||||
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||||
void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input);
|
void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input);
|
||||||
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type);
|
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type);
|
||||||
void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int slot);
|
void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int slot);
|
||||||
void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input);
|
void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input);
|
||||||
|
void utf16_to_text (dsd_state * state, uint8_t wr, uint16_t len, uint8_t * input);
|
||||||
|
void utf8_to_text (dsd_state * state, uint8_t wr, uint16_t len, uint8_t * input);
|
||||||
|
|
||||||
//"DMR STEREO"
|
//"DMR STEREO"
|
||||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1131,12 +1409,53 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state);
|
|||||||
//dmr data header and multi block types (header, 1/2, 3/4, 1, Unified)
|
//dmr data header and multi block types (header, 1/2, 3/4, 1, Unified)
|
||||||
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t dheader_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||||
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type);
|
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type);
|
||||||
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
|
||||||
|
//dmr pdu handling
|
||||||
|
void dmr_sd_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||||
|
void dmr_udp_comp_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||||
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state);
|
void dmr_reset_blocks (dsd_opts * opts, dsd_state * state);
|
||||||
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint16_t len, uint32_t source, uint32_t dest, uint8_t * DMR_PDU);
|
||||||
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
void dmr_locn (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * DMR_PDU);
|
||||||
char * getTimeL(void);
|
|
||||||
char * getDateL(void);
|
//p25 pdu handling
|
||||||
|
uint8_t p25_decrypt_pdu(dsd_opts * opts, dsd_state * state, uint8_t * input, uint8_t alg_id, uint16_t key_id, unsigned long long int mi, int len);
|
||||||
|
uint8_t p25_decode_es_header(dsd_opts * opts, dsd_state * state, uint8_t * input, uint8_t * sap, int * ptr, int len);
|
||||||
|
uint8_t p25_decode_es_header_2(dsd_opts * opts, dsd_state * state, uint8_t * input, int * ptr, int len);
|
||||||
|
void p25_decode_extended_address(dsd_opts * opts, dsd_state * state, uint8_t * input, uint8_t * sap, int * ptr);
|
||||||
|
void p25_decode_pdu_trunking(dsd_opts * opts, dsd_state * state, uint8_t * mpdu_byte);
|
||||||
|
void p25_decode_pdu_header(dsd_opts * opts, dsd_state * state, uint8_t * input);
|
||||||
|
void p25_decode_pdu_data(dsd_opts * opts, dsd_state * state, uint8_t * input, int len);
|
||||||
|
void p25_decode_rsp(uint8_t C, uint8_t T, uint8_t S, char * rsp_string);
|
||||||
|
void p25_decode_sap(uint8_t SAP, char * sap_string);
|
||||||
|
|
||||||
|
//misc pdu
|
||||||
|
void decode_ip_pdu (dsd_opts * opts, dsd_state * state, uint16_t len, uint8_t * input);
|
||||||
|
void decode_cellocator(dsd_opts * opts, dsd_state * state, uint8_t * input, int len);
|
||||||
|
void decode_ars(dsd_opts * opts, dsd_state * state, uint8_t * input, int len);
|
||||||
|
|
||||||
|
//Time and Date Functions
|
||||||
|
char * getTime();
|
||||||
|
char * getTimeC();
|
||||||
|
char * getTimeN(time_t t);
|
||||||
|
char * getTimeF(time_t t);
|
||||||
|
char * getDate();
|
||||||
|
char * getDateH();
|
||||||
|
char * getDateS();
|
||||||
|
char * getDateN(time_t t);
|
||||||
|
char * getDateF(time_t t);
|
||||||
|
|
||||||
|
//event history functions
|
||||||
|
void init_event_history (Event_History_I * event_struct, uint8_t start, uint8_t stop);
|
||||||
|
void push_event_history (Event_History_I * event_struct);
|
||||||
|
void write_event_to_log_file (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t swrite, char * event_string);
|
||||||
|
void watchdog_event_history (dsd_opts * opts, dsd_state * state, uint8_t slot);
|
||||||
|
void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot);
|
||||||
|
void watchdog_event_datacall (dsd_opts * opts, dsd_state * state, uint32_t src, uint32_t dst, char * data_string, uint8_t slot);
|
||||||
|
|
||||||
|
//edacs AFS things
|
||||||
|
int isCustomAfsString(dsd_state * state);
|
||||||
|
int getAfsStringLength(dsd_state * state);
|
||||||
|
int getAfsString(dsd_state * state, char * buffer, int a, int f, int s);
|
||||||
|
|
||||||
//dmr alg stuff
|
//dmr alg stuff
|
||||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1249,6 +1568,31 @@ void edacs(dsd_opts * opts, dsd_state * state);
|
|||||||
unsigned long long int edacs_bch (unsigned long long int message);
|
unsigned long long int edacs_bch (unsigned long long int message);
|
||||||
void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC
|
void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC
|
||||||
|
|
||||||
|
//Generic Tuning Functions
|
||||||
|
void return_to_cc (dsd_opts * opts, dsd_state * state);
|
||||||
|
|
||||||
|
//initialize static float filter memory
|
||||||
|
void init_rrc_filter_memory();
|
||||||
|
|
||||||
|
//misc audio filtering for analog
|
||||||
|
long int raw_rms(short *samples, int len, int step);
|
||||||
|
void init_audio_filters(dsd_state * state);
|
||||||
|
void lpf(dsd_state * state, short * input, int len);
|
||||||
|
void hpf(dsd_state * state, short * input, int len);
|
||||||
|
void pbf(dsd_state * state, short * input, int len);
|
||||||
|
void nf(dsd_state * state, short * input, int len);
|
||||||
|
void hpf_dL(dsd_state * state, short * input, int len);
|
||||||
|
void hpf_dR(dsd_state * state, short * input, int len);
|
||||||
|
//from: https://github.com/NedSimao/FilteringLibrary
|
||||||
|
void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS);
|
||||||
|
float LPFilter_Update(LPFilter *filter, float v_in);
|
||||||
|
void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS);
|
||||||
|
float HPFilter_Update(HPFilter *filter, float v_in);
|
||||||
|
void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS);
|
||||||
|
float PBFilter_Update(PBFilter *filter, float v_in);
|
||||||
|
void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS);
|
||||||
|
float NOTCHFilter_Update(NOTCHFilter *filter, float vin);
|
||||||
|
|
||||||
//csv imports
|
//csv imports
|
||||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||||
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
||||||
@@ -1258,7 +1602,53 @@ int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
|||||||
|
|
||||||
//UDP Socket Connect and UDP Socket Blaster (audio output)
|
//UDP Socket Connect and UDP Socket Blaster (audio output)
|
||||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state);
|
int udp_socket_connect(dsd_opts * opts, dsd_state * state);
|
||||||
int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
int udp_socket_connectA(dsd_opts * opts, dsd_state * state);
|
||||||
|
void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||||
|
void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||||
|
|
||||||
|
//RC4 function prototypes
|
||||||
|
void rc4_voice_decrypt (int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[]);
|
||||||
|
void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t * output_blocks);
|
||||||
|
|
||||||
|
//DES function prototypes
|
||||||
|
void des_multi_keystream_output (unsigned long long int mi, unsigned long long int key_ulli, uint8_t * output, int type, int len);
|
||||||
|
void tdea_multi_keystream_output (unsigned long long int mi, uint8_t * key, uint8_t * output, int type, int len);
|
||||||
|
|
||||||
|
//AES function prototypes
|
||||||
|
void aes_ofb_keystream_output (uint8_t * iv, uint8_t * key, uint8_t * output, int type, int nblocks);
|
||||||
|
void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de);
|
||||||
|
void aes_cbc_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de);
|
||||||
|
void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de);
|
||||||
|
void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
|
||||||
|
void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type);
|
||||||
|
|
||||||
|
//Tytera / Retevis / Anytone / Kenwood / Misc DMR Encryption Modes
|
||||||
|
void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int fnum);
|
||||||
|
void tyt_ep_aes_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void retevis_rc2_keystream_creation(dsd_state *state, char *input);
|
||||||
|
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void anytone_bp_keystream_creation(dsd_state * state, char * input);
|
||||||
|
void baofeng_ap_pc5_keystream_creation(dsd_state *state, char *input);
|
||||||
|
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24]);
|
||||||
|
void straight_mod_xor_keystream_creation(dsd_state * state, char * input);
|
||||||
|
|
||||||
|
//Kirisun
|
||||||
|
uint32_t kirisun_lfsr(unsigned long long int mi);
|
||||||
|
void kirisun_adv_keystream_creation(dsd_state *state);
|
||||||
|
void kirisun_uni_keystream_creation(dsd_state *state);
|
||||||
|
|
||||||
|
//Hytera Enhanced
|
||||||
|
void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value);
|
||||||
|
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len);
|
||||||
|
void hytera_enhanced_alg_refresh(dsd_state * state);
|
||||||
|
|
||||||
|
//LFSR to expand either a DMR 32-bit or P25/NXDN 64-bit MI into a 128-bit IV for AES
|
||||||
|
void lfsr_64_to_128(uint8_t * iv);
|
||||||
|
void LFSR128(dsd_state * state);
|
||||||
|
void LFSR128n(dsd_state * state);
|
||||||
|
void LFSR128d(dsd_state * state);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -1281,6 +1671,9 @@ int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
|
|||||||
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
|
||||||
int isch_lookup (uint64_t isch); //isch map lookup
|
int isch_lookup (uint64_t isch); //isch map lookup
|
||||||
|
|
||||||
|
//Phase 1 NID Check
|
||||||
|
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
|
|
||||||
#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
|
||||||
#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
|
|
||||||
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the
|
|
||||||
* NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity.
|
|
||||||
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
|
|
||||||
* be large enough to accommodate for an integer.
|
|
||||||
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
|
|
||||||
* be able to accommodate 3 chars.
|
|
||||||
* \param parity Input. The parity value read.
|
|
||||||
* \return 0 if there were errors processing the NID.
|
|
||||||
*/
|
|
||||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
|
||||||
95
include/pc4.h
Normal file
95
include/pc4.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef TYT_AP
|
||||||
|
#define TYT_AP
|
||||||
|
|
||||||
|
#define nbround 254
|
||||||
|
#define n1 264
|
||||||
|
|
||||||
|
#define UNUSEDPC4(x) ((void)x)
|
||||||
|
|
||||||
|
/* Structure holding all PC4 state variables */
|
||||||
|
typedef struct {
|
||||||
|
short bits[49], temp[49];
|
||||||
|
uint8_t ptconvert;
|
||||||
|
uint8_t convert[7];
|
||||||
|
uint8_t perm[16][256];
|
||||||
|
uint8_t new1[256];
|
||||||
|
uint8_t array[49];
|
||||||
|
uint8_t array2[49];
|
||||||
|
uint8_t decal[nbround];
|
||||||
|
uint8_t rngxor[nbround][3];
|
||||||
|
uint8_t rngxor2[nbround][3];
|
||||||
|
uint8_t rounds;
|
||||||
|
uint8_t tab[256];
|
||||||
|
uint8_t inv[256];
|
||||||
|
uint8_t permut[3][3];
|
||||||
|
uint64_t bb;
|
||||||
|
uint64_t x;
|
||||||
|
uint8_t tot[3];
|
||||||
|
uint8_t l[2][3], r[2][3];
|
||||||
|
uint8_t y, totb;
|
||||||
|
uint32_t result;
|
||||||
|
uint8_t xyz, count;
|
||||||
|
uint8_t keys[16];
|
||||||
|
unsigned char array_arc4[256];
|
||||||
|
int i_arc4, j_arc4;
|
||||||
|
int x1, x2, i;
|
||||||
|
unsigned char h2[n1];
|
||||||
|
unsigned char h1[n1*3];
|
||||||
|
} PC4Context;
|
||||||
|
|
||||||
|
/* Global context accessible from all .c files */
|
||||||
|
extern PC4Context ctx;
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
void create_keys(PC4Context *ctx, unsigned char key1[], size_t size1);
|
||||||
|
void pc4encrypt(PC4Context *ctx);
|
||||||
|
void pc4decrypt(PC4Context *ctx);
|
||||||
|
void binhex(PC4Context *ctx, short *z, int length);
|
||||||
|
void hexbin(PC4Context *ctx, short *q, uint8_t w, uint8_t hex);
|
||||||
|
static void u64_to_bytes_be(uint64_t val, unsigned char *out);
|
||||||
|
|
||||||
|
/* Encrypt a 49-bit frame (original flow) */
|
||||||
|
static void encrypt_frame_49(short frame_bits_in[49]) {
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = frame_bits_in[i];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.temp[i] = ctx.bits[ctx.array[i]];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = ctx.temp[i];
|
||||||
|
ctx.ptconvert = 0;
|
||||||
|
binhex(&ctx, ctx.bits, 48);
|
||||||
|
pc4encrypt(&ctx);
|
||||||
|
for (int q = 0; q < 6; q++) {
|
||||||
|
uint8_t w = (uint8_t)(q * 8);
|
||||||
|
hexbin(&ctx, ctx.bits, w, ctx.convert[q]);
|
||||||
|
}
|
||||||
|
ctx.bits[48] = (short)(ctx.bits[48] ^ ctx.totb);
|
||||||
|
for (int i = 0; i < 49; i++) ctx.temp[ctx.array2[i]] = ctx.bits[i];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = ctx.temp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt a 49-bit frame (original flow) */
|
||||||
|
static void decrypt_frame_49(short frame_bits_in[49]) {
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = frame_bits_in[i];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.temp[i] = ctx.bits[ctx.array2[i]];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = ctx.temp[i];
|
||||||
|
ctx.ptconvert = 0;
|
||||||
|
binhex(&ctx, ctx.bits, 48);
|
||||||
|
pc4decrypt(&ctx);
|
||||||
|
for (int q = 0; q < 6; q++) {
|
||||||
|
uint8_t w = (uint8_t)(q * 8);
|
||||||
|
hexbin(&ctx, ctx.bits, w, ctx.convert[q]);
|
||||||
|
}
|
||||||
|
ctx.bits[48] = (short)(ctx.bits[48] ^ ctx.totb);
|
||||||
|
for (int i = 0; i < 49; i++) ctx.temp[ctx.array[i]] = ctx.bits[i];
|
||||||
|
for (int i = 0; i < 49; i++) ctx.bits[i] = ctx.temp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert 64-bit integer to bytes (big-endian) */
|
||||||
|
static void u64_to_bytes_be(uint64_t val, unsigned char *out) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
147
include/pc5.h
Normal file
147
include/pc5.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef BAOFENG_AP
|
||||||
|
#define BAOFENG_AP
|
||||||
|
|
||||||
|
#define nbround 254
|
||||||
|
#define n1 264
|
||||||
|
|
||||||
|
#define UNUSEDPC5(x) ((void)x)
|
||||||
|
|
||||||
|
/* Structure holding all PC5 state variables */
|
||||||
|
typedef struct {
|
||||||
|
short bits[49], temp[49];
|
||||||
|
uint8_t ptconvert;
|
||||||
|
uint8_t convert[7];
|
||||||
|
uint8_t perm[16][256];
|
||||||
|
uint8_t new1[256];
|
||||||
|
uint8_t array[49];
|
||||||
|
uint8_t array2[49];
|
||||||
|
uint8_t decal[nbround];
|
||||||
|
uint8_t rngxor[nbround][3];
|
||||||
|
uint8_t rngxor2[nbround][3];
|
||||||
|
uint8_t rounds;
|
||||||
|
uint8_t tab[256];
|
||||||
|
uint8_t inv[256];
|
||||||
|
uint8_t permut[3][3];
|
||||||
|
uint64_t bb;
|
||||||
|
uint64_t x;
|
||||||
|
uint8_t tot[3];
|
||||||
|
uint8_t l[2][3], r[2][3];
|
||||||
|
uint8_t y, totb;
|
||||||
|
uint32_t result;
|
||||||
|
uint8_t xyz, count;
|
||||||
|
uint8_t keys[16];
|
||||||
|
unsigned char array_arc4[256];
|
||||||
|
int i_arc4, j_arc4;
|
||||||
|
int x1, x2, i;
|
||||||
|
unsigned char h2[n1];
|
||||||
|
unsigned char h1[n1*3];
|
||||||
|
uint8_t numbers[25];
|
||||||
|
} PC5Context;
|
||||||
|
|
||||||
|
/* Global context accessible from all .c files */
|
||||||
|
extern PC5Context ctxpc5;
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
void create_keys_pc5(PC5Context *ctxpc5, unsigned char key1[], size_t size1);
|
||||||
|
void pc5encrypt(PC5Context *ctxpc5);
|
||||||
|
void pc5decrypt(PC5Context *ctxpc5);
|
||||||
|
void binhexpc5(PC5Context *ctxpc5, short *z, int length);
|
||||||
|
void hexbinpc5(PC5Context *ctxpc5, short *q, uint8_t w, uint8_t hex);
|
||||||
|
static void u64_to_bytes_be_pc5(uint64_t val, unsigned char *out);
|
||||||
|
|
||||||
|
/* Encrypt a 49-bit frame using PC5 algorithm (original flow) */
|
||||||
|
static void encrypt_frame_49_pc5(short frame_bits_in[49]) {
|
||||||
|
// Only process first 24 bits for encryption, rest are XORed
|
||||||
|
ctxpc5.ptconvert = 0;
|
||||||
|
binhexpc5(&ctxpc5, frame_bits_in, 24);
|
||||||
|
|
||||||
|
uint8_t convert[6];
|
||||||
|
|
||||||
|
// Store first 3 bytes in convert
|
||||||
|
for (int i = 0; i < 3; i++) convert[i] = ctxpc5.convert[i];
|
||||||
|
|
||||||
|
// Split each byte into two 4-bit nibbles
|
||||||
|
ctxpc5.convert[0] = convert[0] >> 4;
|
||||||
|
ctxpc5.convert[1] = convert[0] & 0xF;
|
||||||
|
ctxpc5.convert[2] = convert[1] >> 4;
|
||||||
|
ctxpc5.convert[3] = convert[1] & 0xF;
|
||||||
|
ctxpc5.convert[4] = convert[2] >> 4;
|
||||||
|
ctxpc5.convert[5] = convert[2] & 0xF;
|
||||||
|
|
||||||
|
pc5encrypt(&ctxpc5);
|
||||||
|
|
||||||
|
// Store encrypted nibbles back in convert
|
||||||
|
for (int i = 0; i < 6; i++) convert[i] = ctxpc5.convert[i];
|
||||||
|
|
||||||
|
// Recombine nibbles into bytes
|
||||||
|
ctxpc5.convert[0] = (convert[0] << 4) + convert[1];
|
||||||
|
ctxpc5.convert[1] = (convert[2] << 4) + convert[3];
|
||||||
|
ctxpc5.convert[2] = (convert[4] << 4) + convert[5];
|
||||||
|
|
||||||
|
// Convert back to bits for first 24 bits
|
||||||
|
for (int q = 0; q < 3; q++) {
|
||||||
|
uint8_t w = (uint8_t)(q * 8);
|
||||||
|
hexbinpc5(&ctxpc5, frame_bits_in, w, ctxpc5.convert[q]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR the remaining bits (positions 24 to 48)
|
||||||
|
for (int i = 24; i < 49; i++) {
|
||||||
|
frame_bits_in[i] = (short)(frame_bits_in[i] ^ ctxpc5.numbers[i - 24]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 49; i++) ctxpc5.bits[i] = frame_bits_in[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt a 49-bit frame using PC5 algorithm (original flow) */
|
||||||
|
static void decrypt_frame_49_pc5(short frame_bits_in[49]) {
|
||||||
|
// XOR the remaining bits (positions 24 to 48) first
|
||||||
|
for (int i = 24; i < 49; i++) {
|
||||||
|
frame_bits_in[i] = (short)(frame_bits_in[i] ^ ctxpc5.numbers[i - 24]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxpc5.ptconvert = 0;
|
||||||
|
binhexpc5(&ctxpc5, frame_bits_in, 24);
|
||||||
|
|
||||||
|
uint8_t convert[6];
|
||||||
|
|
||||||
|
// Store first 3 bytes in convert
|
||||||
|
for (int i = 0; i < 3; i++) convert[i] = ctxpc5.convert[i];
|
||||||
|
|
||||||
|
// Split each byte into two 4-bit nibbles
|
||||||
|
ctxpc5.convert[0] = convert[0] >> 4;
|
||||||
|
ctxpc5.convert[1] = convert[0] & 0xF;
|
||||||
|
ctxpc5.convert[2] = convert[1] >> 4;
|
||||||
|
ctxpc5.convert[3] = convert[1] & 0xF;
|
||||||
|
ctxpc5.convert[4] = convert[2] >> 4;
|
||||||
|
ctxpc5.convert[5] = convert[2] & 0xF;
|
||||||
|
|
||||||
|
pc5decrypt(&ctxpc5);
|
||||||
|
|
||||||
|
// Store decrypted nibbles back in convert
|
||||||
|
for (int i = 0; i < 6; i++) convert[i] = ctxpc5.convert[i];
|
||||||
|
|
||||||
|
// Recombine nibbles into bytes
|
||||||
|
ctxpc5.convert[0] = (convert[0] << 4) + convert[1];
|
||||||
|
ctxpc5.convert[1] = (convert[2] << 4) + convert[3];
|
||||||
|
ctxpc5.convert[2] = (convert[4] << 4) + convert[5];
|
||||||
|
|
||||||
|
// Convert back to bits for first 24 bits
|
||||||
|
for (int q = 0; q < 3; q++) {
|
||||||
|
uint8_t w = (uint8_t)(q * 8);
|
||||||
|
hexbinpc5(&ctxpc5, frame_bits_in, w, ctxpc5.convert[q]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 49; i++) ctxpc5.bits[i] = frame_bits_in[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert 64-bit integer to bytes (big-endian) */
|
||||||
|
static void u64_to_bytes_be_pc5(uint64_t val, unsigned char *out) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
43
include/rc2.h
Normal file
43
include/rc2.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef RETEVIS_AP
|
||||||
|
#define RETEVIS_AP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
#define n1 264
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t array_rc4[256];
|
||||||
|
int i_rc4, j_rc4;
|
||||||
|
uint64_t x;
|
||||||
|
uint8_t xyz, count;
|
||||||
|
uint64_t bb;
|
||||||
|
} RC4State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x1, x2;
|
||||||
|
unsigned char h2[n1];
|
||||||
|
unsigned char h1[n1 * 3];
|
||||||
|
} MD2State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t xkey[64];
|
||||||
|
uint8_t plain[8];
|
||||||
|
uint8_t cipher[8];
|
||||||
|
} RC2State;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
RC4State rc4;
|
||||||
|
MD2State md2;
|
||||||
|
RC2State rc2;
|
||||||
|
uint64_t internal_state;
|
||||||
|
uint64_t internal_zero;
|
||||||
|
uint8_t keys[16];
|
||||||
|
} CryptoContext;
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
|
void create_keys_rc2(CryptoContext* ctx, unsigned char key1[], size_t size1);
|
||||||
|
void encryption_rc2(CryptoContext* ctx, uint8_t s1[49]);
|
||||||
|
void decrypt_rc2(CryptoContext* ctx, uint8_t bits[49]);
|
||||||
|
|
||||||
|
#endif
|
||||||
48
include/synctype.h
Normal file
48
include/synctype.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef SYNCTYPE_H
|
||||||
|
#define SYNCTYPE_H
|
||||||
|
|
||||||
|
static const char * SyncTypes[44] = {
|
||||||
|
"P25p1",
|
||||||
|
"P25p1",
|
||||||
|
"X2TDMA DATA",
|
||||||
|
"X2TDMA DATA",
|
||||||
|
"X2TDMA VOICE",
|
||||||
|
"X2TDMA VOICE",
|
||||||
|
"DSTAR", //voice
|
||||||
|
"DSTAR", //voice
|
||||||
|
"M17",
|
||||||
|
"M17",
|
||||||
|
"DMR", //10
|
||||||
|
"DMR",
|
||||||
|
"DMR",
|
||||||
|
"DMR",
|
||||||
|
"EDACS/PV",
|
||||||
|
"EDACS/PV",
|
||||||
|
"M17", //M17 Voice Stream
|
||||||
|
"M17", //M17 Voice Stream
|
||||||
|
"DSTAR", //header
|
||||||
|
"DSTAR", //header
|
||||||
|
"dPMR", //20
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"dPMR",
|
||||||
|
"NXDN",
|
||||||
|
"NXDN",
|
||||||
|
"YSF", //30
|
||||||
|
"YSF", //31
|
||||||
|
"DMR",
|
||||||
|
"DMR",
|
||||||
|
"DMR",
|
||||||
|
"P25p2",
|
||||||
|
"P25p2",
|
||||||
|
"EDACS/PV", //37
|
||||||
|
"EDACS/PV", //38
|
||||||
|
"ANALOG", //39 Generic Sync Types
|
||||||
|
"DIGITAL" //40 Generic Sync Types
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
44
package.nix
Normal file
44
package.nix
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, cmake
|
||||||
|
, mbelib
|
||||||
|
, libsndfile
|
||||||
|
, ncurses
|
||||||
|
, pulseaudio
|
||||||
|
, rtl-sdr
|
||||||
|
, codec2
|
||||||
|
, portaudioSupport ? true
|
||||||
|
, portaudio ? null
|
||||||
|
}:
|
||||||
|
|
||||||
|
assert portaudioSupport -> portaudio != null;
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "dsd-fme";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ cmake ];
|
||||||
|
buildInputs = [
|
||||||
|
mbelib
|
||||||
|
libsndfile
|
||||||
|
rtl-sdr
|
||||||
|
ncurses.dev
|
||||||
|
pulseaudio.dev
|
||||||
|
codec2
|
||||||
|
] ++ lib.optionals portaudioSupport [ portaudio ];
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Digital Speech Decoder - Florida Man Edition";
|
||||||
|
longDescription = ''
|
||||||
|
DSD is able to decode several digital voice formats from discriminator
|
||||||
|
tap audio and synthesize the decoded speech. Speech synthesis requires
|
||||||
|
mbelib, which is a separate package.
|
||||||
|
'';
|
||||||
|
homepage = "https://github.com/lwvmobile/dsd-fme";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
diff --git a/src/dmr_block.c b/src/dmr_block.c
|
|
||||||
index 893b0e8..e7f9de7 100644
|
|
||||||
--- a/src/dmr_block.c
|
|
||||||
+++ b/src/dmr_block.c
|
|
||||||
@@ -783,6 +783,6 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
|
||||||
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
|
|
||||||
// sprintf (state->call_string[0], "%s", " "); //21 spaces
|
|
||||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
|
||||||
- sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
|
||||||
- sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
|
||||||
+ // sprintf (state->dmr_lrrp_gps[0], "%s", ""); //disabled for dmr data call persistence #174
|
|
||||||
+ // sprintf (state->dmr_lrrp_gps[1], "%s", ""); //disabled for dmr data call persistence #174
|
|
||||||
}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/dmr_data.c b/src/dmr_data.c
|
|
||||||
index 3541152..3cae906 100644
|
|
||||||
--- a/src/dmr_data.c
|
|
||||||
+++ b/src/dmr_data.c
|
|
||||||
@@ -267,7 +267,20 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|
||||||
state->color_code_ok = SlotTypeOk;
|
|
||||||
|
|
||||||
//not sure why I still have two variables for this, need to look and see what state->color_code still ties into
|
|
||||||
- if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
|
|
||||||
+ if (SlotTypeOk == 1)
|
|
||||||
+ {
|
|
||||||
+ if (state->dmr_color_code != state->color_code)
|
|
||||||
+ {
|
|
||||||
+ //Zero out values on color code change #174
|
|
||||||
+ state->lasttg = 0;
|
|
||||||
+ state->lasttgR =0;
|
|
||||||
+ state->lastsrc = 0;
|
|
||||||
+ state->lastsrcR = 0;
|
|
||||||
+ sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
|
||||||
+ sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
|
||||||
+ state->dmr_color_code = state->color_code;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* Reconstitute the burst type */
|
|
||||||
burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 5531ef3..5598793 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -257,10 +257,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
//zero out right away if not trunking
|
|
||||||
if (opts->p25_trunk == 0)
|
|
||||||
{
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
|
|
||||||
//zero out vc frequencies?
|
|
||||||
state->p25_vc_freq[0] = 0;
|
|
||||||
@@ -290,10 +290,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
//mainly bugfix for ncurses and per call wavs (edacs) and also signal fade, etc
|
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && time(NULL) - state->last_cc_sync_time > opts->trunk_hangtime)
|
|
||||||
{
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -431,7 +431,7 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len));
|
|
||||||
memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
|
|
||||||
memset(state->dmr_embedded_gps, 0, sizeof(state->dmr_embedded_gps));
|
|
||||||
- memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
|
||||||
+ // memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
|
||||||
|
|
||||||
// memset(state->active_channel, 0, sizeof(state->active_channel));
|
|
||||||
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..e9ecab1 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -3104,7 +3104,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//LRRP
|
|
||||||
- if(state->dmrburstL != 16) //only during data and no trunking
|
|
||||||
+ // if(state->dmrburstL != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
|
||||||
{
|
|
||||||
attron(COLOR_PAIR(4));
|
|
||||||
printw ("%s", state->dmr_lrrp_gps[0]);
|
|
||||||
@@ -3298,7 +3298,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//LRRP
|
|
||||||
- if(state->dmrburstR != 16) //only during data and no trunking
|
|
||||||
+ // if(state->dmrburstR != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
|
||||||
{
|
|
||||||
attron(COLOR_PAIR(4));
|
|
||||||
printw ("%s", state->dmr_lrrp_gps[1]);
|
|
||||||
@@ -3978,10 +3978,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
dmr_reset_blocks (opts, state);
|
|
||||||
|
|
||||||
//zero out additional items
|
|
||||||
- state->lasttg = 0;
|
|
||||||
- state->lasttgR = 0;
|
|
||||||
- state->lastsrc = 0;
|
|
||||||
- state->lastsrcR = 0;
|
|
||||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
|
||||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
|
||||||
index 5155bd7..3cf0480 100644
|
|
||||||
--- a/src/p25p2_vpdu.c
|
|
||||||
+++ b/src/p25p2_vpdu.c
|
|
||||||
@@ -155,16 +155,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -255,16 +255,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -386,16 +386,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -511,16 +511,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -642,16 +642,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -748,16 +748,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channel & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channel & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -918,16 +918,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1109,16 +1109,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1245,16 +1245,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (tunable_chan & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (tunable_chan & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1374,16 +1374,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
- if (channelt & 1) //VCH1
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
- }
|
|
||||||
- else //VCH0
|
|
||||||
- {
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- }
|
|
||||||
+ // if (channelt & 1) //VCH1
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 0;
|
|
||||||
+ // opts->slot2_on = 1;
|
|
||||||
+ // }
|
|
||||||
+ // else //VCH0
|
|
||||||
+ // {
|
|
||||||
+ // opts->slot1_on = 1;
|
|
||||||
+ // opts->slot2_on = 0;
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
diff --git a/src/p25p1_mdpu.c b/src/p25p1_mdpu.c
|
|
||||||
index 7d29860..00c1828 100644
|
|
||||||
--- a/src/p25p1_mdpu.c
|
|
||||||
+++ b/src/p25p1_mdpu.c
|
|
||||||
@@ -527,13 +527,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -644,13 +644,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -753,13 +753,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -876,13 +876,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/p25p1_tsbk.c b/src/p25p1_tsbk.c
|
|
||||||
index c801b7f..345335a 100644
|
|
||||||
--- a/src/p25p1_tsbk.c
|
|
||||||
+++ b/src/p25p1_tsbk.c
|
|
||||||
@@ -294,13 +294,13 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
|
||||||
index 468b71a..1b14d71 100644
|
|
||||||
--- a/src/p25p2_vpdu.c
|
|
||||||
+++ b/src/p25p2_vpdu.c
|
|
||||||
@@ -75,8 +75,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
|
|
||||||
//Temp Fix: Disable Slot Playback when MAC_SIGNAL present (good CRC),
|
|
||||||
//during trunking, will re-enable when call grant is received, prevent lagging:
|
|
||||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot1_on = 0;
|
|
||||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot2_on = 0;
|
|
||||||
|
|
||||||
//TODO: Iron out issues with audio playing in every non SACCH slot when no voice present
|
|
||||||
//without it stuttering during actual voice
|
|
||||||
@@ -156,13 +154,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -256,13 +254,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -387,13 +385,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -512,13 +510,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -643,13 +641,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -749,13 +747,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channel & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -919,13 +917,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1110,13 +1108,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1246,13 +1244,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (tunable_chan & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1375,13 +1373,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1498,13 +1496,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
|
||||||
if (channelt & 1) //VCH1
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot2_on = 1;
|
|
||||||
+ //opts->slot1_on = 0;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
}
|
|
||||||
else //VCH0
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ //opts->slot2_on = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1516,9 +1514,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
|
||||||
state->samplesPerSymbol = 10;
|
|
||||||
state->symbolCenter = 4;
|
|
||||||
opts->frame_p25p1 = 1; //enable, just in case it isn't already
|
|
||||||
-
|
|
||||||
- //enable voice on slot 1 (just in case they start talking too, but probably won't)
|
|
||||||
- opts->slot1_on = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
330
patch/extra/ghost_box_wip3_awd.patch
Normal file
330
patch/extra/ghost_box_wip3_awd.patch
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
diff --git a/include/dsd.h b/include/dsd.h
|
||||||
|
index 4a75702..3cf085e 100644
|
||||||
|
--- a/include/dsd.h
|
||||||
|
+++ b/include/dsd.h
|
||||||
|
@@ -317,6 +317,7 @@ typedef struct
|
||||||
|
long int rtl_rms;
|
||||||
|
int monitor_input_audio;
|
||||||
|
int analog_only;
|
||||||
|
+ int ghosts_only;
|
||||||
|
int pulse_raw_rate_in;
|
||||||
|
int pulse_raw_rate_out;
|
||||||
|
int pulse_digi_rate_in;
|
||||||
|
@@ -1342,6 +1343,8 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency);
|
||||||
|
long int GetCurrentFreq(int sockfd);
|
||||||
|
bool SetFreq(int sockfd, long int freq);
|
||||||
|
bool SetModulation(int sockfd, int bandwidth);
|
||||||
|
+bool SetModulationWFM(int sockfd, int bandwidth);
|
||||||
|
+void death (dsd_opts * opts, dsd_state * state);
|
||||||
|
//commands below unique to GQRX only, not usable on SDR++
|
||||||
|
bool GetSignalLevel(int sockfd, double *dBFS);
|
||||||
|
bool GetSquelchLevel(int sockfd, double *dBFS);
|
||||||
|
diff --git a/src/3.c b/src/3.c
|
||||||
|
index e104993..b9033bd 100644
|
||||||
|
--- a/src/3.c
|
||||||
|
+++ b/src/3.c
|
||||||
|
@@ -591,4 +591,176 @@ long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as
|
||||||
|
rms = (long int)sqrt((p-err) / len);
|
||||||
|
if (rms < 0) rms = 150;
|
||||||
|
return rms;
|
||||||
|
-}
|
||||||
|
\ No newline at end of file
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+//Ghosts
|
||||||
|
+void death (dsd_opts * opts, dsd_state * state)
|
||||||
|
+{
|
||||||
|
+ int i, x, result = 0;
|
||||||
|
+ short ghosts[960];
|
||||||
|
+ short spooks[960];
|
||||||
|
+ short demons[960];
|
||||||
|
+ short sample = 0;
|
||||||
|
+
|
||||||
|
+ memset (ghosts, 0, 960*sizeof(short));
|
||||||
|
+ memset (spooks, 0, 960*sizeof(short));
|
||||||
|
+ memset (demons, 0, 960*sizeof(short));
|
||||||
|
+
|
||||||
|
+ while (!exitflag) //while the software is running
|
||||||
|
+ {
|
||||||
|
+ //death on speaks at 48k/1 short output
|
||||||
|
+ if (opts->audio_in_type == 0)
|
||||||
|
+ {
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
+ ghosts[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
+ spooks[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
|
||||||
|
+ demons[i] = sample;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (opts->audio_in_type == 8)
|
||||||
|
+ {
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
+ if (result == 0)
|
||||||
|
+ {
|
||||||
|
+ sf_close(opts->tcp_file_in);
|
||||||
|
+ fprintf (stderr, "Connection to the Underworld Severed.\n");
|
||||||
|
+ fprintf (stderr, "Closing Death Speech Decoder.\n");
|
||||||
|
+ cleanupAndExit(opts, state);
|
||||||
|
+ }
|
||||||
|
+ ghosts[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
+ if (result == 0)
|
||||||
|
+ {
|
||||||
|
+ sf_close(opts->tcp_file_in);
|
||||||
|
+ fprintf (stderr, "Connection to the Underworld Severed.\n");
|
||||||
|
+ fprintf (stderr, "Closing Death Speech Decoder.\n");
|
||||||
|
+ cleanupAndExit(opts, state);
|
||||||
|
+ }
|
||||||
|
+ spooks[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
|
+ if (result == 0)
|
||||||
|
+ {
|
||||||
|
+ sf_close(opts->tcp_file_in);
|
||||||
|
+ fprintf (stderr, "Connection to the Underworld Severed.\n");
|
||||||
|
+ fprintf (stderr, "Closing Death Speech Decoder.\n");
|
||||||
|
+ cleanupAndExit(opts, state);
|
||||||
|
+ }
|
||||||
|
+ demons[i] = sample;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //RTL Input
|
||||||
|
+ #ifdef USE_RTLSDR
|
||||||
|
+ if (opts->audio_in_type == 3)
|
||||||
|
+ {
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
+ ghosts[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
+ spooks[i] = sample;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 960; i++)
|
||||||
|
+ {
|
||||||
|
+ get_rtlsdr_sample(&sample, opts, state);
|
||||||
|
+ demons[i] = sample;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ #endif
|
||||||
|
+
|
||||||
|
+ //The Dead Don't Like OSS input yet
|
||||||
|
+
|
||||||
|
+ //Listen to the Howls of the Deceased
|
||||||
|
+ if (opts->audio_out_type == 0 && opts->slot1_on == 1)
|
||||||
|
+ {
|
||||||
|
+ pa_simple_write(opts->pulse_raw_dev_out, ghosts, 960*2, NULL);
|
||||||
|
+ pa_simple_write(opts->pulse_raw_dev_out, spooks, 960*2, NULL);
|
||||||
|
+ pa_simple_write(opts->pulse_raw_dev_out, demons, 960*2, NULL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (opts->audio_out_type == 8) //UDP Audio
|
||||||
|
+ {
|
||||||
|
+ udp_socket_blasterA (opts, state, 960*2, ghosts);
|
||||||
|
+ udp_socket_blasterA (opts, state, 960*2, spooks);
|
||||||
|
+ udp_socket_blasterA (opts, state, 960*2, demons);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //added a condition check so that if OSS output and 8K, switches to 48K when opening OSS
|
||||||
|
+ if (opts->audio_out_type == 5 && opts->floating_point == 0 && opts->slot1_on == 1)
|
||||||
|
+ {
|
||||||
|
+ write (opts->audio_out_fd, ghosts, 960*2);
|
||||||
|
+ write (opts->audio_out_fd, spooks, 960*2);
|
||||||
|
+ write (opts->audio_out_fd, demons, 960*2);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //STDOUT -- I don't see the harm of adding this here, will be fine for analog only or digital only (non-mixed analog and digital)
|
||||||
|
+ if (opts->audio_out_type == 1 && opts->floating_point == 0 && opts->slot1_on == 1)
|
||||||
|
+ {
|
||||||
|
+ write (opts->audio_out_fd, ghosts, 960*2);
|
||||||
|
+ write (opts->audio_out_fd, spooks, 960*2);
|
||||||
|
+ write (opts->audio_out_fd, demons, 960*2);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //Undulate the Crystal Ball
|
||||||
|
+ if (x >= opts->trunk_hangtime)
|
||||||
|
+ {
|
||||||
|
+ long int spook_channel = state->trunk_lcn_freq[0];
|
||||||
|
+
|
||||||
|
+ //rigctl
|
||||||
|
+ if (opts->use_rigctl == 1)
|
||||||
|
+ {
|
||||||
|
+ if (opts->setmod_bw != 0 ) SetModulationWFM(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
+ SetFreq(opts->rigctl_sockfd, spook_channel);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //rtl
|
||||||
|
+ if (opts->audio_in_type == 3)
|
||||||
|
+ {
|
||||||
|
+ #ifdef USE_RTLSDR
|
||||||
|
+ rtl_dev_tune(opts, spook_channel);
|
||||||
|
+ #endif
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ //
|
||||||
|
+ state->trunk_lcn_freq[0] += 200000;
|
||||||
|
+
|
||||||
|
+ if (state->trunk_lcn_freq[0] > 106100000)
|
||||||
|
+ state->trunk_lcn_freq[0] = 87900000;
|
||||||
|
+
|
||||||
|
+ x = 0;
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ x++;
|
||||||
|
+
|
||||||
|
+ } //end while loop
|
||||||
|
+} //end ghosts
|
||||||
|
\ No newline at end of file
|
||||||
|
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||||
|
index ca878e9..f14995d 100644
|
||||||
|
--- a/src/dsd_main.c
|
||||||
|
+++ b/src/dsd_main.c
|
||||||
|
@@ -696,6 +696,7 @@ initOpts (dsd_opts * opts)
|
||||||
|
|
||||||
|
opts->monitor_input_audio = 0; //enable with -8
|
||||||
|
opts->analog_only = 0; //only turned on with -fA
|
||||||
|
+ opts->ghosts_only = 0; //ghostbox mode with -fG
|
||||||
|
|
||||||
|
opts->inverted_p2 = 0;
|
||||||
|
opts->p2counter = 0;
|
||||||
|
@@ -1358,6 +1359,7 @@ usage ()
|
||||||
|
printf ("Decoder options:\n");
|
||||||
|
printf (" -fa Auto Detection\n");
|
||||||
|
printf (" -fA Passive Analog Audio Monitor\n");
|
||||||
|
+ printf (" -fG Ghosts, Demons, Specters, Ghouls, and Skeletons (Ghost Box)\n");
|
||||||
|
printf (" -ft TDMA Trunking P25p1 Control and Voice, P25p2 Trunked Channels, and DMR\n");
|
||||||
|
printf (" -fs DMR TDMA BS and MS Simplex\n");
|
||||||
|
printf (" -f1 Decode only P25 Phase 1\n");
|
||||||
|
@@ -2172,6 +2174,35 @@ main (int argc, char **argv)
|
||||||
|
sprintf (opts.output_name, "Analog Monitor");
|
||||||
|
fprintf (stderr,"Only Monitoring Passive Analog Signal\n");
|
||||||
|
}
|
||||||
|
+ else if (optarg[0] == 'G') //listen to spooky scary skeletons
|
||||||
|
+ {
|
||||||
|
+ opts.frame_dstar = 0;
|
||||||
|
+ opts.frame_x2tdma = 0;
|
||||||
|
+ opts.frame_p25p1 = 0;
|
||||||
|
+ opts.frame_p25p2 = 0;
|
||||||
|
+ opts.frame_nxdn48 = 0;
|
||||||
|
+ opts.frame_nxdn96 = 0;
|
||||||
|
+ opts.frame_dmr = 0;
|
||||||
|
+ opts.frame_dpmr = 0;
|
||||||
|
+ opts.frame_provoice = 0;
|
||||||
|
+ opts.frame_ysf = 0;
|
||||||
|
+ opts.frame_m17 = 0;
|
||||||
|
+ opts.pulse_digi_rate_out = 8000;
|
||||||
|
+ opts.pulse_digi_out_channels = 1;
|
||||||
|
+ opts.dmr_stereo = 0;
|
||||||
|
+ state.dmr_stereo = 0;
|
||||||
|
+ opts.dmr_mono = 0;
|
||||||
|
+ state.rf_mod = 0;
|
||||||
|
+ opts.monitor_input_audio = 1;
|
||||||
|
+ opts.ghosts_only = 1;
|
||||||
|
+ state.trunk_lcn_freq[0] = 87900000; //everybody knows ghosts live on the Broadcast FM band
|
||||||
|
+ opts.setmod_bw = 150000; //Ghosts annunciate clearly with about 150,000 PB
|
||||||
|
+ opts.trunk_hangtime = 0;
|
||||||
|
+ opts.rtlsdr_center_freq = 850000000;
|
||||||
|
+ opts.rtl_bandwidth = 48;
|
||||||
|
+ sprintf (opts.output_name, "Ghost Box");
|
||||||
|
+ fprintf (stderr,"Sounds of the Dead.\n");
|
||||||
|
+ }
|
||||||
|
else if (optarg[0] == 'd')
|
||||||
|
{
|
||||||
|
opts.frame_dstar = 1;
|
||||||
|
@@ -3462,6 +3493,22 @@ main (int argc, char **argv)
|
||||||
|
processM17IPF(&opts, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ else if (opts.ghosts_only == 1)
|
||||||
|
+ {
|
||||||
|
+ #ifdef USE_RTLSDR
|
||||||
|
+ if(opts.audio_in_type == 3)
|
||||||
|
+ open_rtlsdr_stream(&opts);
|
||||||
|
+ #endif
|
||||||
|
+
|
||||||
|
+ if (opts.audio_in_type == 0)
|
||||||
|
+ openPulseInput(&opts);
|
||||||
|
+
|
||||||
|
+ if (opts.audio_out_type == 0)
|
||||||
|
+ openPulseOutput(&opts);
|
||||||
|
+
|
||||||
|
+ death(&opts, &state);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
diff --git a/src/dsd_rigctl.c b/src/dsd_rigctl.c
|
||||||
|
index 820ac7e..f12bacc 100644
|
||||||
|
--- a/src/dsd_rigctl.c
|
||||||
|
+++ b/src/dsd_rigctl.c
|
||||||
|
@@ -163,6 +163,28 @@ bool SetModulation(int sockfd, int bandwidth)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool SetModulationWFM(int sockfd, int bandwidth)
|
||||||
|
+{
|
||||||
|
+ char buf[BUFSIZE];
|
||||||
|
+ //the bandwidth is now a user/system based configurable variable
|
||||||
|
+ sprintf (buf, "M WFM %d\n", bandwidth); //SDR++ has changed the token from FM to NFM, even if Ryzerth fixes it later, users may still have an older version
|
||||||
|
+ Send(sockfd, buf);
|
||||||
|
+ Recv(sockfd, buf);
|
||||||
|
+
|
||||||
|
+ //if it fails the first time, send the other token instead
|
||||||
|
+ if (strcmp(buf, "RPRT 1\n") == 0 ) //sdr++ has a linebreak here, is that in all versions of the protocol?
|
||||||
|
+ {
|
||||||
|
+ sprintf (buf, "M WFM %d\n", bandwidth); //anything not SDR++
|
||||||
|
+ Send(sockfd, buf);
|
||||||
|
+ Recv(sockfd, buf);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (strcmp(buf, "RPRT 1\n") == 0 )
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool GetSignalLevel(int sockfd, double *dBFS)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp
|
||||||
|
index ad04667..dd6566c 100644
|
||||||
|
--- a/src/rtl_sdr_fm.cpp
|
||||||
|
+++ b/src/rtl_sdr_fm.cpp
|
||||||
|
@@ -1034,7 +1034,7 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||||
|
//init with low pass if decoding P25 or EDACS/Provoice
|
||||||
|
if (opts->frame_p25p1 == 1 || opts->frame_p25p2 == 1 || opts->frame_provoice == 1)
|
||||||
|
demod_init_ro2(&demod);
|
||||||
|
- else if (opts->analog_only == 1 || opts->m17encoder == 1)
|
||||||
|
+ else if (opts->analog_only == 1 || opts->m17encoder == 1 || opts->ghosts_only == 1)
|
||||||
|
demod_init_analog(&demod);
|
||||||
|
else demod_init(&demod);
|
||||||
|
output_init(&output);
|
||||||
@@ -1,461 +0,0 @@
|
|||||||
diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c
|
|
||||||
index 129a087..0b7f4e2 100644
|
|
||||||
--- a/src/dmr_csbk.c
|
|
||||||
+++ b/src/dmr_csbk.c
|
|
||||||
@@ -424,6 +424,25 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
+ if (state->currentslot == 0)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ else if (state->currentslot == 1)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
|
||||||
@@ -443,6 +462,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
+
|
|
||||||
+ if (state->currentslot == 0)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ else if (state->currentslot == 1)
|
|
||||||
+ {
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
uint32_t tempf = (uint32_t)state->p25_cc_freq;
|
|
||||||
if (opts->rtlsdr_center_freq != tempf)
|
|
||||||
diff --git a/src/dmr_flco.c b/src/dmr_flco.c
|
|
||||||
index 828de02..916eb62 100644
|
|
||||||
--- a/src/dmr_flco.c
|
|
||||||
+++ b/src/dmr_flco.c
|
|
||||||
@@ -10,6 +10,38 @@
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
+//I really just need to make ONE consolidated date and time function that works correctly
|
|
||||||
+char * getDateFLC(void) {
|
|
||||||
+ #ifdef AERO_BUILD
|
|
||||||
+ char datename[80];
|
|
||||||
+ #else
|
|
||||||
+ char datename[99];
|
|
||||||
+ #endif
|
|
||||||
+ char * curr2;
|
|
||||||
+ struct tm * to;
|
|
||||||
+ time_t t;
|
|
||||||
+ t = time(NULL);
|
|
||||||
+ to = localtime( & t);
|
|
||||||
+ strftime(datename, sizeof(datename), "%Y%m%d", to);
|
|
||||||
+ curr2 = strtok(datename, " ");
|
|
||||||
+ return curr2;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
|
||||||
+char * getTimeFLC(void) //get pretty hhmmss timestamp
|
|
||||||
+{
|
|
||||||
+ char * curr = (char *) malloc(9);
|
|
||||||
+ time_t t = time(NULL);
|
|
||||||
+ struct tm * ptm = localtime(& t);
|
|
||||||
+ sprintf(
|
|
||||||
+ curr,
|
|
||||||
+ "%02d%02d%02d",
|
|
||||||
+ ptm->tm_hour,
|
|
||||||
+ ptm->tm_min,
|
|
||||||
+ ptm->tm_sec
|
|
||||||
+ );
|
|
||||||
+ return curr;
|
|
||||||
+}
|
|
||||||
|
|
||||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
|
||||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
|
||||||
@@ -304,6 +336,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
state->dmr_so = so;
|
|
||||||
state->lasttg = target;
|
|
||||||
state->lastsrc = source;
|
|
||||||
+ char * timestr;
|
|
||||||
+ timestr = getTimeFLC();
|
|
||||||
+ //open wav file here if not already opened
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f == NULL)
|
|
||||||
+ {
|
|
||||||
+ sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
|
||||||
+ openWavOutFileL (opts, state);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
if (state->currentslot == 1)
|
|
||||||
{
|
|
||||||
@@ -311,6 +351,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
state->dmr_soR = so;
|
|
||||||
state->lasttgR = target;
|
|
||||||
state->lastsrcR = source;
|
|
||||||
+ char * timestr;
|
|
||||||
+ timestr = getTimeFLC();
|
|
||||||
+ //open wav file here if not already opened
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR == NULL)
|
|
||||||
+ {
|
|
||||||
+ sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
|
||||||
+ openWavOutFileR (opts, state);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
|
||||||
@@ -337,6 +385,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gain = opts->audio_gain;
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
if (state->currentslot == 1)
|
|
||||||
{
|
|
||||||
@@ -350,6 +404,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|
||||||
//reset gain
|
|
||||||
if (opts->floating_point == 1)
|
|
||||||
state->aout_gainR = opts->audio_gain;
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
diff --git a/src/dsd_file.c b/src/dsd_file.c
|
|
||||||
index 8e9094c..e8441ec 100644
|
|
||||||
--- a/src/dsd_file.c
|
|
||||||
+++ b/src/dsd_file.c
|
|
||||||
@@ -366,7 +366,7 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
fclose (opts->mbe_out_f);
|
|
||||||
opts->mbe_out_f = NULL;
|
|
||||||
opts->mbe_out = 0;
|
|
||||||
- fprintf (stderr, "\nClosing MBE out file 1.\n");
|
|
||||||
+ // fprintf (stderr, "\nClosing MBE out file 1.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -385,7 +385,7 @@ void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
fclose (opts->mbe_out_fR);
|
|
||||||
opts->mbe_out_fR = NULL;
|
|
||||||
opts->mbe_outR = 0;
|
|
||||||
- fprintf (stderr, "\nClosing MBE out file 2.\n");
|
|
||||||
+ // fprintf (stderr, "\nClosing MBE out file 2.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -420,7 +420,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
state->tgcount = 0;
|
|
||||||
-
|
|
||||||
+ //TODO: Change the date/time functions here to operate without using colons
|
|
||||||
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
|
|
||||||
|
|
||||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
|
||||||
@@ -467,7 +467,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
state->tgcount = 0;
|
|
||||||
-
|
|
||||||
+ //TODO: Change the date/time functions here to operate without using colons
|
|
||||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
|
|
||||||
|
|
||||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
|
|
||||||
@@ -557,6 +557,19 @@ void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_file, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileF %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
+
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
|
||||||
@@ -564,6 +577,19 @@ void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_f);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_file, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileL %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
+
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
@@ -571,6 +597,18 @@ void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
|
||||||
UNUSED(state);
|
|
||||||
|
|
||||||
sf_close(opts->wav_out_fR);
|
|
||||||
+ char shell[2065], newfilename[1032];
|
|
||||||
+ int result;
|
|
||||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_fileR);
|
|
||||||
+#ifdef AERO_BUILD
|
|
||||||
+ result = rename (opts->wav_out_fileR, newfilename);
|
|
||||||
+ UNUSED(shell);
|
|
||||||
+#else
|
|
||||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_fileR, newfilename);
|
|
||||||
+ result = system (shell);
|
|
||||||
+#endif
|
|
||||||
+ // fprintf (stderr, "\n Close WAV FileR %s; Result: %d \n", newfilename, result);
|
|
||||||
+ UNUSED(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..c3a216d 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -107,6 +107,19 @@ void
|
|
||||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
|
|
||||||
+ //close any perCall wav files that are open
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileL (opts, state);
|
|
||||||
+ opts->wav_out_f = NULL;
|
|
||||||
+ }
|
|
||||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
|
||||||
+ {
|
|
||||||
+ closeWavOutFileR (opts, state);
|
|
||||||
+ opts->wav_out_fR = NULL;
|
|
||||||
+ }
|
|
||||||
+ //end perCall wav file close
|
|
||||||
+
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
//TODO: Investigate why getSymbol needs to be run first in this context...truly confused here
|
|
||||||
if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
@@ -1568,9 +1581,9 @@ main (int argc, char **argv)
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
|
||||||
+ fprintf (stderr, "Build Version: AW (20231214) G Build\n");
|
|
||||||
#else
|
|
||||||
- fprintf (stderr, "Build Version: AW %s \n", GIT_TAG);
|
|
||||||
+ fprintf (stderr, "Build Version: AW %s G Build\n", GIT_TAG);
|
|
||||||
#endif
|
|
||||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
|
||||||
|
|
||||||
diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c
|
|
||||||
index 9f609ca..f23209c 100644
|
|
||||||
--- a/src/dsd_mbe.c
|
|
||||||
+++ b/src/dsd_mbe.c
|
|
||||||
@@ -1191,7 +1191,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|
||||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
|
||||||
{
|
|
||||||
//write wav to per call on left channel Slot 1
|
|
||||||
- writeSynthesizedVoice (opts, state);
|
|
||||||
+ if (opts->wav_out_f != NULL)
|
|
||||||
+ writeSynthesizedVoice (opts, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1201,7 +1202,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
|
||||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
|
||||||
{
|
|
||||||
//write wav to per call on right channel Slot 2
|
|
||||||
- writeSynthesizedVoiceR (opts, state);
|
|
||||||
+ if (opts->wav_out_fR != NULL)
|
|
||||||
+ writeSynthesizedVoiceR (opts, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..ab5497e 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -999,7 +999,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (choicec == 12)
|
|
||||||
{
|
|
||||||
//flesh out all closewavs and sprint "" wav filenames
|
|
||||||
- closeWavOutFile (opts, state);
|
|
||||||
+ // closeWavOutFile (opts, state);
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
closeWavOutFileR (opts, state);
|
|
||||||
//closeWavOutFileRaw (opts, state);
|
|
||||||
@@ -2063,6 +2063,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (opts->dmr_stereo_wav == 1 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN
|
|
||||||
{
|
|
||||||
//close old first, assign name based on time and radio, open wav file
|
|
||||||
+ if (opts->wav_out_f != NULL)
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
sprintf (opts->wav_out_file, "./%s/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), timestr, rn, tgn, src);
|
|
||||||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
@@ -2105,13 +2106,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[9][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rd and tg are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileL (opts, state);
|
|
||||||
- sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_f != NULL)
|
|
||||||
+ // closeWavOutFileL (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
|
||||||
{
|
|
||||||
@@ -2126,7 +2128,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
|
|
||||||
//DMR BS Slot 1 - matrix 0-4
|
|
||||||
- if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
|
||||||
+ if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 ) ) //|| lls == 35 || lls == 36
|
|
||||||
{
|
|
||||||
|
|
||||||
for (short int k = 0; k < 4; k++)
|
|
||||||
@@ -2147,14 +2149,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[4][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rd and tg are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileL (opts, state);
|
|
||||||
-
|
|
||||||
- sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_f != NULL)
|
|
||||||
+ // closeWavOutFileL (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
|
||||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
|
||||||
{
|
|
||||||
@@ -2190,20 +2192,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
call_matrix[9][5] = time(NULL);
|
|
||||||
|
|
||||||
//open wav file if enabled and both rdR and tgR are not 0
|
|
||||||
- if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
|
||||||
- {
|
|
||||||
- //close old first, assign name based on time and radio, open wav file
|
|
||||||
- closeWavOutFileR (opts, state);
|
|
||||||
- sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
|
||||||
- openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
|
||||||
- }
|
|
||||||
+ // if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //close old first, assign name based on time and radio, open wav file
|
|
||||||
+ // if (opts->wav_out_fR != NULL)
|
|
||||||
+ // closeWavOutFileR (opts, state);
|
|
||||||
+ // sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
|
||||||
+ // openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
- if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
|
||||||
- {
|
|
||||||
- //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
|
||||||
- beeper (opts, state, 1);
|
|
||||||
- state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
|
||||||
- }
|
|
||||||
+ // if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
|
||||||
+ // {
|
|
||||||
+ // //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
|
||||||
+ // beeper (opts, state, 1);
|
|
||||||
+ // state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1]));
|
|
||||||
sprintf (state->dmr_embedded_gps[1], "%s", "");
|
|
||||||
@@ -2275,7 +2278,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (opts->ncurses_compact == 1)
|
|
||||||
{
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
- printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)");
|
|
||||||
+ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231214)");
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
}
|
|
||||||
#elif LIMAZULUTWEAKS
|
|
||||||
@@ -2313,13 +2316,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
|
||||||
#endif
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
- if (i == 5) printw (" %s ", "Aero Build");
|
|
||||||
- if (i == 6) printw (" AW (20231015) \n");
|
|
||||||
+ if (i == 5) printw (" %s ", "G Build");
|
|
||||||
+ if (i == 6) printw (" AW (20231214) \n");
|
|
||||||
#elif ZDEV_BUILD
|
|
||||||
- if (i == 5) printw (" %s ", "AW ");
|
|
||||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
|
||||||
#else
|
|
||||||
- if (i == 5) printw (" %s ", "AW ");
|
|
||||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
|
||||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
|
||||||
#endif
|
|
||||||
else printw ("\n");
|
|
||||||
@@ -3913,7 +3916,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (c == 112) //'p' key - stop all per call wav files
|
|
||||||
{
|
|
||||||
//hope this one doesn't cause random crashing or garbage writing
|
|
||||||
- closeWavOutFile (opts, state);
|
|
||||||
+ // closeWavOutFile (opts, state);
|
|
||||||
closeWavOutFileL (opts, state);
|
|
||||||
closeWavOutFileR (opts, state);
|
|
||||||
sprintf (opts->wav_out_file, "%s", "");
|
|
||||||
257
patch/moto_type2_starter_pack.patch
Normal file
257
patch/moto_type2_starter_pack.patch
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
diff --git a/include/dsd.h b/include/dsd.h
|
||||||
|
index 4a75702..355837f 100644
|
||||||
|
--- a/include/dsd.h
|
||||||
|
+++ b/include/dsd.h
|
||||||
|
@@ -357,6 +357,8 @@ typedef struct
|
||||||
|
int frame_m17;
|
||||||
|
int inverted_m17;
|
||||||
|
|
||||||
|
+ int frame_typeii;
|
||||||
|
+
|
||||||
|
FILE *symbolfile;
|
||||||
|
int call_alert;
|
||||||
|
|
||||||
|
@@ -989,6 +991,10 @@ typedef struct
|
||||||
|
#define INV_DPMR_FRAME_SYNC_3 "311313111133"
|
||||||
|
#define INV_DPMR_FRAME_SYNC_4 "111333331133131131111313"
|
||||||
|
|
||||||
|
+//Motorola Type II Sync Pattern 0xAC binary 1010 1100
|
||||||
|
+#define TYPE_II_SYNC "13131133" //baesd on what getDibit returns
|
||||||
|
+#define TYPE_II_SINV "31313311" //baesd on what getDibit returns
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* function prototypes
|
||||||
|
*/
|
||||||
|
@@ -1357,6 +1363,9 @@ void edacs(dsd_opts * opts, dsd_state * state);
|
||||||
|
unsigned long long int edacs_bch (unsigned long long int message);
|
||||||
|
void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC
|
||||||
|
|
||||||
|
+//Type II
|
||||||
|
+void type_ii(dsd_opts * opts, dsd_state * state);
|
||||||
|
+
|
||||||
|
//Generic Tuning Functions
|
||||||
|
void return_to_cc (dsd_opts * opts, dsd_state * state);
|
||||||
|
|
||||||
|
diff --git a/src/dsd_dibit.c b/src/dsd_dibit.c
|
||||||
|
index 5424f7a..9b403cf 100644
|
||||||
|
--- a/src/dsd_dibit.c
|
||||||
|
+++ b/src/dsd_dibit.c
|
||||||
|
@@ -222,13 +222,14 @@ invert_dibit(int dibit)
|
||||||
|
int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||||
|
{
|
||||||
|
// determine dibit state
|
||||||
|
- if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37))
|
||||||
|
+ if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37) || (state->synctype == 40))
|
||||||
|
|
||||||
|
{
|
||||||
|
// 6 +D-STAR
|
||||||
|
// 14 +ProVoice
|
||||||
|
// 18 +D-STAR_HD
|
||||||
|
// 37 +EDACS
|
||||||
|
+ // 41 +TypeII
|
||||||
|
|
||||||
|
if (symbol > state->center)
|
||||||
|
{
|
||||||
|
@@ -243,12 +244,13 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||||
|
return (1); // +3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19) || (state->synctype == 38))
|
||||||
|
+ else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19) || (state->synctype == 38) || (state->synctype == 41))
|
||||||
|
{
|
||||||
|
// 7 -D-STAR
|
||||||
|
// 15 -ProVoice
|
||||||
|
// 19 -D-STAR_HD
|
||||||
|
// 38 -EDACS
|
||||||
|
+ // 41 -TypeII
|
||||||
|
|
||||||
|
if (symbol > state->center)
|
||||||
|
{
|
||||||
|
diff --git a/src/dsd_frame.c b/src/dsd_frame.c
|
||||||
|
index 577169c..58fa07c 100644
|
||||||
|
--- a/src/dsd_frame.c
|
||||||
|
+++ b/src/dsd_frame.c
|
||||||
|
@@ -269,6 +269,12 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||||
|
processYSF(opts, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+ //TypeII
|
||||||
|
+ else if (state->synctype == 40 || state->synctype == 41)
|
||||||
|
+ {
|
||||||
|
+ type_ii(opts, state);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
//M17
|
||||||
|
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) ||
|
||||||
|
(state->synctype == 76) || (state->synctype == 77) || (state->synctype == 86) || (state->synctype == 87) ||
|
||||||
|
diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c
|
||||||
|
index e10f3cc..7f5fbf5 100644
|
||||||
|
--- a/src/dsd_frame_sync.c
|
||||||
|
+++ b/src/dsd_frame_sync.c
|
||||||
|
@@ -117,6 +117,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||||
|
* 36 = -P25 P2
|
||||||
|
* 37 = +EDACS
|
||||||
|
* 38 = -EDACS
|
||||||
|
+ * 40 = +Type2
|
||||||
|
+ * 41 = -Type2
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@@ -205,7 +207,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
t_max = 12; //based on Frame_Sync_2 pattern
|
||||||
|
}
|
||||||
|
- else if (opts->frame_m17 == 1)
|
||||||
|
+ else if (opts->frame_m17 == 1 || opts->frame_typeii == 1)
|
||||||
|
{
|
||||||
|
t_max = 8;
|
||||||
|
}
|
||||||
|
@@ -581,6 +583,40 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||||
|
}
|
||||||
|
//end YSF sync
|
||||||
|
|
||||||
|
+ //Motorola Type II
|
||||||
|
+ strncpy(synctest8, (synctest_p - 7), 8);
|
||||||
|
+ if (opts->frame_typeii == 1)
|
||||||
|
+ {
|
||||||
|
+ if (strcmp(synctest8, TYPE_II_SYNC) == 0)
|
||||||
|
+ {
|
||||||
|
+ if (state->lastsynctype == 40)
|
||||||
|
+ {
|
||||||
|
+ printFrameSync (opts, state, "+Type II", synctest_pos + 1, modulation);
|
||||||
|
+ state->carrier = 1;
|
||||||
|
+ state->offset = synctest_pos;
|
||||||
|
+ state->max = ((state->max) + lmax) / 2;
|
||||||
|
+ state->min = ((state->min) + lmin) / 2;
|
||||||
|
+ state->lastsynctype = 40;
|
||||||
|
+ return (40);
|
||||||
|
+ }
|
||||||
|
+ else state->lastsynctype = 40;
|
||||||
|
+ }
|
||||||
|
+ else if (strcmp(synctest8, TYPE_II_SINV) == 0)
|
||||||
|
+ {
|
||||||
|
+ if (state->lastsynctype == 41)
|
||||||
|
+ {
|
||||||
|
+ printFrameSync (opts, state, "-Type II", synctest_pos + 1, modulation);
|
||||||
|
+ state->carrier = 1;
|
||||||
|
+ state->offset = synctest_pos;
|
||||||
|
+ state->max = ((state->max) + lmax) / 2;
|
||||||
|
+ state->min = ((state->min) + lmin) / 2;
|
||||||
|
+ state->lastsynctype = 41;
|
||||||
|
+ return (41);
|
||||||
|
+ }
|
||||||
|
+ else state->lastsynctype = 41;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
//M17 Sync -- Just STR and LSF for now
|
||||||
|
strncpy(synctest16, (synctest_p - 15), 16);
|
||||||
|
strncpy(synctest8, (synctest_p - 7), 8);
|
||||||
|
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||||
|
index ca878e9..c5a3e95 100644
|
||||||
|
--- a/src/dsd_main.c
|
||||||
|
+++ b/src/dsd_main.c
|
||||||
|
@@ -622,6 +622,7 @@ initOpts (dsd_opts * opts)
|
||||||
|
opts->frame_provoice = 0;
|
||||||
|
opts->frame_ysf = 1;
|
||||||
|
opts->frame_m17 = 0;
|
||||||
|
+ opts->frame_typeii = 0;
|
||||||
|
opts->mod_c4fm = 1;
|
||||||
|
opts->mod_qpsk = 0;
|
||||||
|
opts->mod_gfsk = 0;
|
||||||
|
@@ -1377,6 +1378,7 @@ usage ()
|
||||||
|
printf (" -fe Decode only EDACS EA/ProVoice*\n");
|
||||||
|
printf (" -fE Decode only EDACS EA/ProVoice with ESK 0xA0*\n");
|
||||||
|
printf (" -fm Decode only dPMR*\n");
|
||||||
|
+ printf (" -fT Decode only Type II (Smartnet/Smartzone)*\n");
|
||||||
|
printf (" -l Disable DMR, dPMR, NXDN, M17 input filtering\n");
|
||||||
|
printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
||||||
|
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||||
|
@@ -2431,6 +2433,39 @@ main (int argc, char **argv)
|
||||||
|
opts.rtl_bandwidth = 24;
|
||||||
|
// opts.rtl_gain_value = 36;
|
||||||
|
}
|
||||||
|
+ else if (optarg[0] == 'T') //Motorola Type II
|
||||||
|
+ {
|
||||||
|
+ opts.frame_dstar = 0;
|
||||||
|
+ opts.frame_x2tdma = 0;
|
||||||
|
+ opts.frame_p25p1 = 0;
|
||||||
|
+ opts.frame_p25p2 = 0;
|
||||||
|
+ opts.frame_nxdn48 = 0;
|
||||||
|
+ opts.frame_nxdn96 = 0;
|
||||||
|
+ opts.frame_dmr = 0;
|
||||||
|
+ opts.frame_dpmr = 0;
|
||||||
|
+ opts.frame_provoice = 0;
|
||||||
|
+ opts.frame_ysf = 0;
|
||||||
|
+ opts.frame_m17 = 0;
|
||||||
|
+ opts.frame_typeii = 1;
|
||||||
|
+ ////to maintain 10/4 sample per symbol rate, we need to run at 36000
|
||||||
|
+ //to hit TypeII's 3600 bps rating. BW values in rtl_fm are also modified
|
||||||
|
+ //similarly, but testing will need to be done, this MAY NOT be viable in DSD-FME.
|
||||||
|
+ opts.pulse_digi_rate_in = 36000;
|
||||||
|
+ opts.wav_sample_rate = 36000;
|
||||||
|
+ opts.mod_c4fm = 1;
|
||||||
|
+ opts.mod_qpsk = 0;
|
||||||
|
+ opts.mod_gfsk = 0; //might still be better as gfsk
|
||||||
|
+ state.rf_mod = 2;
|
||||||
|
+ opts.pulse_digi_rate_out = 8000;
|
||||||
|
+ opts.pulse_digi_out_channels = 1;
|
||||||
|
+ opts.dmr_stereo = 0;
|
||||||
|
+ opts.dmr_mono = 0;
|
||||||
|
+ state.dmr_stereo = 0;
|
||||||
|
+ // opts.setmod_bw = 12500;
|
||||||
|
+ sprintf (opts.output_name, "Type II");
|
||||||
|
+ // fprintf (stderr,"Setting symbol rate to 4800 / second\n");
|
||||||
|
+ fprintf (stderr,"Decoding Motorola Type II frames.\n");
|
||||||
|
+ }
|
||||||
|
else if (optarg[0] == '1')
|
||||||
|
{
|
||||||
|
opts.frame_dstar = 0;
|
||||||
|
diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp
|
||||||
|
index ad04667..954c6dc 100644
|
||||||
|
--- a/src/rtl_sdr_fm.cpp
|
||||||
|
+++ b/src/rtl_sdr_fm.cpp
|
||||||
|
@@ -1025,6 +1025,7 @@ void rtlsdr_sighandler()
|
||||||
|
void open_rtlsdr_stream(dsd_opts *opts)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
+ if (opts->frame_typeii == 1) bandwidth_divisor = 36000;
|
||||||
|
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
|
||||||
|
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
|
||||||
|
volume_multiplier = 1; //moved to external handling to be more dynamic
|
||||||
|
diff --git a/src/typeII.c b/src/typeII.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..eb0cd56
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/typeII.c
|
||||||
|
@@ -0,0 +1,29 @@
|
||||||
|
+/*-------------------------------------------------------------------------------
|
||||||
|
+ * typeII.c
|
||||||
|
+ * Motorola Type II Decoder (WIP)
|
||||||
|
+ *
|
||||||
|
+ *
|
||||||
|
+ *
|
||||||
|
+ *
|
||||||
|
+ * LWVMOBILE
|
||||||
|
+ * 2024-03 DSD-FME Florida Man Edition
|
||||||
|
+ *-----------------------------------------------------------------------------*/
|
||||||
|
+
|
||||||
|
+#include "dsd.h"
|
||||||
|
+
|
||||||
|
+//Type II
|
||||||
|
+void type_ii(dsd_opts * opts, dsd_state * state)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+ uint8_t t2[80]; memset(t2, 0, sizeof(t2));
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 76; i++)
|
||||||
|
+ t2[i] = getDibit(opts, state);
|
||||||
|
+
|
||||||
|
+ //debug dump collected bits
|
||||||
|
+ fprintf (stderr, "Frame:");
|
||||||
|
+ for (i = 0; i < 10; i++)
|
||||||
|
+ fprintf (stderr, " %02X", (uint8_t)ConvertBitIntoBytes(&t2[i*8], 8));
|
||||||
|
+
|
||||||
|
+ fprintf (stderr, "\n");
|
||||||
|
+}
|
||||||
|
\ No newline at end of file
|
||||||
@@ -1,769 +0,0 @@
|
|||||||
diff --git a/include/dsd.h b/include/dsd.h
|
|
||||||
index 0b47dee..f459528 100644
|
|
||||||
--- a/include/dsd.h
|
|
||||||
+++ b/include/dsd.h
|
|
||||||
@@ -437,8 +437,8 @@ typedef struct
|
|
||||||
//new stereo short sample storage
|
|
||||||
short s_l[160]; //single sample left
|
|
||||||
short s_r[160]; //single sample right
|
|
||||||
- short s_l4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
- short s_r4[4][160]; //quad sample for up to a P25p2 4V
|
|
||||||
+ short s_l4[36][160]; //quad sample for up to a P25p2 4V
|
|
||||||
+ short s_r4[36][160]; //quad sample for up to a P25p2 4V
|
|
||||||
//new stereo short sample storage tapped from 48_k internal upsampling
|
|
||||||
short s_lu[160*6]; //single sample left
|
|
||||||
short s_ru[160*6]; //single sample right
|
|
||||||
@@ -654,6 +654,7 @@ typedef struct
|
|
||||||
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
|
||||||
int ess_b[2][96]; //external storage for ESS_B fragments
|
|
||||||
int fourv_counter[2]; //external reference counter for ESS_B fragment collection
|
|
||||||
+ int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe
|
|
||||||
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
|
||||||
|
|
||||||
//iden freq storage for frequency calculations
|
|
||||||
@@ -926,6 +927,7 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //floa
|
|
||||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
|
||||||
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
|
||||||
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe
|
|
||||||
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
|
||||||
//
|
|
||||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
|
||||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
|
||||||
index a836afc..5eaf3c4 100644
|
|
||||||
--- a/src/dsd_audio2.c
|
|
||||||
+++ b/src/dsd_audio2.c
|
|
||||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+//short stereo mix 18v superframe
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ //NOTE: This will run once every superframe during a sacch field
|
|
||||||
+ //exact implementation to be determined
|
|
||||||
+
|
|
||||||
+ int i, j;
|
|
||||||
+ uint8_t encL, encR;
|
|
||||||
+
|
|
||||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
|
||||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
|
||||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
|
||||||
+
|
|
||||||
+ short empty[320];
|
|
||||||
+ memset (empty, 1, sizeof(empty));
|
|
||||||
+
|
|
||||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
|
||||||
+ encL = encR = 1;
|
|
||||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
|
||||||
+ encL = 0;
|
|
||||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
|
||||||
+ encR = 0;
|
|
||||||
+
|
|
||||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
|
||||||
+ if (encL)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algid == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->R != 0)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (encR)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algidR == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->RR != 0)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ //TODO: add option to bypass enc with a toggle as well
|
|
||||||
+
|
|
||||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
+ //its not really 'disabled', we just aren't playing it
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //WIP: Mute if on B list (or not W list)
|
|
||||||
+ char modeL[8];
|
|
||||||
+ sprintf (modeL, "%s", "");
|
|
||||||
+ char modeR[8];
|
|
||||||
+ sprintf (modeR, "%s", "");
|
|
||||||
+
|
|
||||||
+ int TGL = state->lasttg;
|
|
||||||
+ int TGR = state->lasttgR;
|
|
||||||
+
|
|
||||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
|
||||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
|
||||||
+ if (opts->trunk_use_allow_list == 1)
|
|
||||||
+ {
|
|
||||||
+ sprintf (modeL, "%s", "B");
|
|
||||||
+ sprintf (modeR, "%s", "B");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < state->group_tally; i++)
|
|
||||||
+ {
|
|
||||||
+ if (state->group_array[i].groupNumber == TGL)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ if (state->group_array[i].groupNumber == TGR)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //flag either left or right as 'enc' to mute if B
|
|
||||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //if TG Hold in place, mute anything but that TG #132
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
|
||||||
+ if (encL && encR)
|
|
||||||
+ goto SS18_END;
|
|
||||||
+
|
|
||||||
+ //interleave left and right channels from the short storage area
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ for (i = 0; i < 160; i++)
|
|
||||||
+ {
|
|
||||||
+ if (!encL)
|
|
||||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
|
||||||
+ if (!encR)
|
|
||||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ SS18_END:
|
|
||||||
+
|
|
||||||
+ //run cleanup since we pulled stuff from processAudio
|
|
||||||
+ state->audio_out_idx = 0;
|
|
||||||
+ state->audio_out_idxR = 0;
|
|
||||||
+
|
|
||||||
+ //set float temp buffer to baseline
|
|
||||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
|
||||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2 >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2 = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2R >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2R = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
|
||||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
|
||||||
{
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..02590a6 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -382,6 +382,8 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
|
||||||
}
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
//values displayed in ncurses terminal
|
|
||||||
// state->p25_vc_freq[0] = 0;
|
|
||||||
@@ -745,7 +747,7 @@ initOpts (dsd_opts * opts)
|
|
||||||
//slot preference is used during OSS audio playback to
|
|
||||||
//prefer one tdma voice slot over another when both are playing back
|
|
||||||
//this is a fix to OSS 48k/1 output
|
|
||||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
|
|
||||||
//hardset slots to synthesize
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
@@ -941,6 +943,8 @@ initState (dsd_state * state)
|
|
||||||
}
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
state->K = 0;
|
|
||||||
state->R = 0;
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..fc3f28b 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
|
||||||
if (opts->slot1_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot1_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
|
||||||
if (opts->slot2_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot2_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
}
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot_preference = 1; //slot 2
|
|
||||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 1; //slot 2
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot2_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- opts->slot_preference = 0; //slot 1
|
|
||||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 0; //slot 1
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (c == 51) //'3' key, cycle slot preferences
|
|
||||||
+ {
|
|
||||||
+ if (opts->slot_preference < 2)
|
|
||||||
+ opts->slot_preference++;
|
|
||||||
+ else opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (c == 43) //+ key, increment audio_gain
|
|
||||||
{
|
|
||||||
|
|
||||||
diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c
|
|
||||||
index c391eba..99a4840 100644
|
|
||||||
--- a/src/p25p2_frame.c
|
|
||||||
+++ b/src/p25p2_frame.c
|
|
||||||
@@ -490,18 +490,27 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
// else state->dmrburstR = 21;
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
+
|
|
||||||
+ //unsure of the best location for these counter resets
|
|
||||||
+ if (state->voice_counter[0] >= 18)
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+
|
|
||||||
+ if (state->voice_counter[1] >= 18)
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -509,13 +518,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -523,13 +534,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -537,13 +550,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[3], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[3], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[3], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -709,17 +724,26 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
+ //unsure of the best location for these counter resets
|
|
||||||
+ if (state->voice_counter[0] >= 18)
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+
|
|
||||||
+ if (state->voice_counter[1] >= 18)
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
+
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -727,17 +751,19 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
|
||||||
if(state->currentslot == 0)
|
|
||||||
{
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
|
||||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
|
||||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
|
||||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
|
||||||
}
|
|
||||||
-
|
|
||||||
+ // if (state->currentslot == 0) state->voice_counter[0] = 0; if (state->currentslot == 1) state->voice_counter[1] = 0;
|
|
||||||
process_ESS(opts, state);
|
|
||||||
|
|
||||||
//reset drop bytes after a 2V
|
|
||||||
@@ -930,6 +956,8 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|
||||||
state->p2_is_lcch = 0;
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
|
|
||||||
goto END;
|
|
||||||
}
|
|
||||||
@@ -949,8 +977,32 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
playSynthesizedVoiceFS4 (opts, state);
|
|
||||||
|
|
||||||
- if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
- playSynthesizedVoiceSS4 (opts, state);
|
|
||||||
+ // if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
|
||||||
+ // playSynthesizedVoiceSS4 (opts, state);
|
|
||||||
+
|
|
||||||
+ // fprintf (stderr, " VCH0: %d;", state->voice_counter[0]); //debug
|
|
||||||
+ // fprintf (stderr, " VCH1: %d;", state->voice_counter[1]); //debug
|
|
||||||
+
|
|
||||||
+ //this works, but may still have an element of 'dual voice stutter' which was my initial complaint, but shouldn't 'lag' during trunking operations (hopefully)
|
|
||||||
+ if ( (state->voice_counter[0] >= 18 || state->voice_counter[1] >= 18 ) && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ {
|
|
||||||
+ playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ state->voice_counter[0] = 0; //reset
|
|
||||||
+ state->voice_counter[1] = 0; //reset
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //these two will work, but NOT at the same time on dual voice
|
|
||||||
+ // if (state->voice_counter[0] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ // {
|
|
||||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ // state->voice_counter[0] = 0; //reset
|
|
||||||
+ // }
|
|
||||||
+
|
|
||||||
+ // if (state->voice_counter[1] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
|
||||||
+ // {
|
|
||||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
|
||||||
+ // state->voice_counter[1] = 0; //reset
|
|
||||||
+ // }
|
|
||||||
|
|
||||||
//debug: fix burst indicator for ncurses if marginal signal
|
|
||||||
// if (voice)
|
|
||||||
diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c
|
|
||||||
index 101d1e4..847fe71 100644
|
|
||||||
--- a/src/p25p2_xcch.c
|
|
||||||
+++ b/src/p25p2_xcch.c
|
|
||||||
@@ -122,6 +122,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
|
|
||||||
state->dmrburstL = 20;
|
|
||||||
@@ -171,6 +172,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->payload_algidR = 0; //zero this out as well
|
|
||||||
|
|
||||||
@@ -230,6 +232,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
state->dmrburstL = 23;
|
|
||||||
state->payload_algid = 0;
|
|
||||||
@@ -258,6 +261,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->dmrburstR = 23;
|
|
||||||
state->payload_algidR = 0;
|
|
||||||
@@ -498,6 +502,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
|
|
||||||
state->dmrburstL = 20;
|
|
||||||
@@ -538,6 +543,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
//reset fourv_counter and dropbyte on PTT
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
|
|
||||||
state->dmrburstR = 20;
|
|
||||||
@@ -594,6 +600,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->dropL = 256;
|
|
||||||
state->dmrburstL = 23;
|
|
||||||
state->payload_algid = 0; //zero this out as well
|
|
||||||
@@ -622,6 +629,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
{
|
|
||||||
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->dropR = 256;
|
|
||||||
state->dmrburstR = 23;
|
|
||||||
state->payload_algidR = 0; //zero this out as well
|
|
||||||
@@ -723,6 +731,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->dmrburstL = 24;
|
|
||||||
state->fourv_counter[0] = 0;
|
|
||||||
+ state->voice_counter[0] = 0;
|
|
||||||
state->lastsrc = 0;
|
|
||||||
state->lasttg = 0;
|
|
||||||
|
|
||||||
@@ -733,6 +742,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
|
||||||
state->payload_keyidR = 0;
|
|
||||||
state->dmrburstR = 24;
|
|
||||||
state->fourv_counter[1] = 0;
|
|
||||||
+ state->voice_counter[1] = 0;
|
|
||||||
state->lastsrcR = 0;
|
|
||||||
state->lasttgR = 0;
|
|
||||||
|
|
||||||
@@ -1,452 +0,0 @@
|
|||||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
|
||||||
index a836afc..5eaf3c4 100644
|
|
||||||
--- a/src/dsd_audio2.c
|
|
||||||
+++ b/src/dsd_audio2.c
|
|
||||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
//as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
//its not really 'disabled', we just aren't playing it
|
|
||||||
- if (opts->slot1_on == 0) encL = 1;
|
|
||||||
- if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//WIP: Mute if on B list (or not W list)
|
|
||||||
char modeL[8];
|
|
||||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
//if TG Hold in place, mute anything but that TG #132
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
|
||||||
- //likewise, override and unmute if TG hold matches TG
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
|
||||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
//interleave left and right channels from the short storage area
|
|
||||||
for (i = 0; i < 160; i++)
|
|
||||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+//short stereo mix 18v superframe
|
|
||||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
|
||||||
+{
|
|
||||||
+
|
|
||||||
+ //NOTE: This will run once every superframe during a sacch field
|
|
||||||
+ //exact implementation to be determined
|
|
||||||
+
|
|
||||||
+ int i, j;
|
|
||||||
+ uint8_t encL, encR;
|
|
||||||
+
|
|
||||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
|
||||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
|
||||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
|
||||||
+
|
|
||||||
+ short empty[320];
|
|
||||||
+ memset (empty, 1, sizeof(empty));
|
|
||||||
+
|
|
||||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
|
||||||
+ encL = encR = 1;
|
|
||||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
|
||||||
+ encL = 0;
|
|
||||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
|
||||||
+ encR = 0;
|
|
||||||
+
|
|
||||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
|
||||||
+ if (encL)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algid == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->R != 0)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (encR)
|
|
||||||
+ {
|
|
||||||
+ if (state->payload_algidR == 0xAA)
|
|
||||||
+ {
|
|
||||||
+ if (state->RR != 0)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ //TODO: add option to bypass enc with a toggle as well
|
|
||||||
+
|
|
||||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
|
||||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
|
||||||
+ //its not really 'disabled', we just aren't playing it
|
|
||||||
+ // if (opts->slot1_on == 0) encL = 1;
|
|
||||||
+ // if (opts->slot2_on == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
|
||||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
|
||||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
|
||||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
|
||||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
|
||||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
|
||||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
|
||||||
+
|
|
||||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
|
||||||
+ {
|
|
||||||
+ encL = 1;
|
|
||||||
+ encR = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //WIP: Mute if on B list (or not W list)
|
|
||||||
+ char modeL[8];
|
|
||||||
+ sprintf (modeL, "%s", "");
|
|
||||||
+ char modeR[8];
|
|
||||||
+ sprintf (modeR, "%s", "");
|
|
||||||
+
|
|
||||||
+ int TGL = state->lasttg;
|
|
||||||
+ int TGR = state->lasttgR;
|
|
||||||
+
|
|
||||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
|
||||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
|
||||||
+ if (opts->trunk_use_allow_list == 1)
|
|
||||||
+ {
|
|
||||||
+ sprintf (modeL, "%s", "B");
|
|
||||||
+ sprintf (modeR, "%s", "B");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < state->group_tally; i++)
|
|
||||||
+ {
|
|
||||||
+ if (state->group_array[i].groupNumber == TGL)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ if (state->group_array[i].groupNumber == TGR)
|
|
||||||
+ {
|
|
||||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
|
||||||
+ // break; //need to keep going to check other potential slot group
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //flag either left or right as 'enc' to mute if B
|
|
||||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
|
||||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
|
||||||
+
|
|
||||||
+ //check to see if we need to enable slot and toggle slot preference here
|
|
||||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
|
||||||
+ if (strcmp(modeL, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (strcmp(modeR, "A") == 0)
|
|
||||||
+ {
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //if TG Hold in place, mute anything but that TG #132
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
|
||||||
+ encL = 1;
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
|
||||||
+ encR = 1;
|
|
||||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
|
||||||
+ {
|
|
||||||
+ encL = 0;
|
|
||||||
+ opts->slot1_on = 1;
|
|
||||||
+ opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
|
||||||
+ {
|
|
||||||
+ encR = 0;
|
|
||||||
+ opts->slot2_on = 1;
|
|
||||||
+ opts->slot_preference = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
|
||||||
+ if (encL && encR)
|
|
||||||
+ goto SS18_END;
|
|
||||||
+
|
|
||||||
+ //interleave left and right channels from the short storage area
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ for (i = 0; i < 160; i++)
|
|
||||||
+ {
|
|
||||||
+ if (!encL)
|
|
||||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
|
||||||
+ if (!encR)
|
|
||||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
|
||||||
+ {
|
|
||||||
+ for (j = 0; j < 18; j++)
|
|
||||||
+ {
|
|
||||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
|
||||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ SS18_END:
|
|
||||||
+
|
|
||||||
+ //run cleanup since we pulled stuff from processAudio
|
|
||||||
+ state->audio_out_idx = 0;
|
|
||||||
+ state->audio_out_idxR = 0;
|
|
||||||
+
|
|
||||||
+ //set float temp buffer to baseline
|
|
||||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
|
||||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2 >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2 = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (state->audio_out_idx2R >= 800000)
|
|
||||||
+ {
|
|
||||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
|
||||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
|
||||||
+ state->audio_out_idx2R = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
|
||||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
|
||||||
{
|
|
||||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
|
||||||
index 1d2616b..924bf00 100644
|
|
||||||
--- a/src/dsd_main.c
|
|
||||||
+++ b/src/dsd_main.c
|
|
||||||
@@ -745,7 +745,7 @@ initOpts (dsd_opts * opts)
|
|
||||||
//slot preference is used during OSS audio playback to
|
|
||||||
//prefer one tdma voice slot over another when both are playing back
|
|
||||||
//this is a fix to OSS 48k/1 output
|
|
||||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
|
||||||
|
|
||||||
//hardset slots to synthesize
|
|
||||||
opts->slot1_on = 1;
|
|
||||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
|
||||||
index 4646e77..fc3f28b 100644
|
|
||||||
--- a/src/dsd_ncurses.c
|
|
||||||
+++ b/src/dsd_ncurses.c
|
|
||||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
{
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
|
||||||
if (opts->slot1_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot1_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
|
||||||
if (opts->slot2_on == 0) printw (" OFF");
|
|
||||||
- if (opts->slot2_on == 1) printw (" ON");
|
|
||||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
|
||||||
printw ("\n");
|
|
||||||
}
|
|
||||||
printw ("------------------------------------------------------------------------------\n");
|
|
||||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot1_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot1_on = 0;
|
|
||||||
- opts->slot_preference = 1; //slot 2
|
|
||||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 1; //slot 2
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
|
||||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
|
||||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
//switching, but want to control each seperately plz
|
|
||||||
if (opts->slot2_on == 1)
|
|
||||||
{
|
|
||||||
- opts->slot2_on = 0;
|
|
||||||
- opts->slot_preference = 0; //slot 1
|
|
||||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
|
||||||
+ // opts->slot_preference = 0; //slot 1
|
|
||||||
//clear any previously buffered audio
|
|
||||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
|
||||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
|
||||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (c == 51) //'3' key, cycle slot preferences
|
|
||||||
+ {
|
|
||||||
+ if (opts->slot_preference < 2)
|
|
||||||
+ opts->slot_preference++;
|
|
||||||
+ else opts->slot_preference = 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (c == 43) //+ key, increment audio_gain
|
|
||||||
{
|
|
||||||
|
|
||||||
7
src/1.c
7
src/1.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 1.c
|
|
||||||
* Placeholder File 1 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
7
src/2.c
7
src/2.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 2.c
|
|
||||||
* Placeholder File 2 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
87
src/3.c
87
src/3.c
@@ -1,87 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 3.c
|
|
||||||
* Placeholder File 3 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
* A 1/2 Rate Convolutional Decoder for NXDN/M17/YSF
|
|
||||||
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
|
||||||
|
|
||||||
static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
|
|
||||||
|
|
||||||
// trellis_1_2 encode: source is in bits, result in bits
|
|
||||||
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
|
||||||
{
|
|
||||||
for (int i=0; i<result_len; i+=2) {
|
|
||||||
reg = (reg << 1) | source[i>>1];
|
|
||||||
result[i] = PARITY[reg & 0x19];
|
|
||||||
result[i+1] = PARITY[reg & 0x17];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simplified trellis 2:1 decode; source and result in bits
|
|
||||||
// assumes that encoding was done with NTEST trailing zero bits
|
|
||||||
// result_len should be set to the actual number of data bits
|
|
||||||
// in the original unencoded message (excl. these trailing bits)
|
|
||||||
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
|
||||||
{
|
|
||||||
int reg = 0;
|
|
||||||
int min_d;
|
|
||||||
int min_bt;
|
|
||||||
static const int NTEST = 4;
|
|
||||||
static const int NTESTC = 1 << NTEST;
|
|
||||||
uint8_t bt[NTEST];
|
|
||||||
uint8_t tt[NTEST*2];
|
|
||||||
int dstats[4];
|
|
||||||
int sum;
|
|
||||||
for (int p=0; p < 4; p++)
|
|
||||||
dstats[p] = 0;
|
|
||||||
for (int p=0; p < result_len; p++) {
|
|
||||||
for (int i=0; i<NTESTC; i++) {
|
|
||||||
bt[0] = (i&8)>>3;
|
|
||||||
bt[1] = (i&4)>>2;
|
|
||||||
bt[2] = (i&2)>>1;
|
|
||||||
bt[3] = (i&1);
|
|
||||||
trellis_encode(tt, bt, NTEST*2, reg);
|
|
||||||
sum=0;
|
|
||||||
for (int j=0; j<NTEST*2; j++) {
|
|
||||||
sum += tt[j] ^ source[p*2+j];
|
|
||||||
}
|
|
||||||
if (i == 0 || sum < min_d) {
|
|
||||||
min_d = sum;
|
|
||||||
min_bt = bt[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result[p] = min_bt;
|
|
||||||
reg = (reg << 1) | min_bt;
|
|
||||||
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//debug output
|
|
||||||
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Original Copyright/License
|
|
||||||
|
|
||||||
/* -*- c++ -*- */
|
|
||||||
/*
|
|
||||||
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
|
||||||
*
|
|
||||||
* This file is part of OP25
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this software; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
7
src/4.c
7
src/4.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 4.c
|
|
||||||
* Placeholder File 4 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
7
src/5.c
7
src/5.c
@@ -1,7 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------------
|
|
||||||
* 5.c
|
|
||||||
* Placeholder File 5 -- This file is for temporary code storage
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-----------------------------------------------------------------------------*/
|
|
||||||
922
src/crypt-aes.c
Normal file
922
src/crypt-aes.c
Normal file
@@ -0,0 +1,922 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* aes.c Tinier AES
|
||||||
|
* Easy To Use (and configurable) AES Output and Utility Bit/Byte Functions
|
||||||
|
*
|
||||||
|
* Modified Tiny AES code for more variable nk/nr/nb values, all in one file
|
||||||
|
* https://github.com/kokke/tiny-AES-c
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
#define AES_BLOCKLEN 16
|
||||||
|
unsigned Nb = 4;
|
||||||
|
unsigned Nk = 8;
|
||||||
|
unsigned Nr = 14;
|
||||||
|
|
||||||
|
struct AES_ctx
|
||||||
|
{
|
||||||
|
uint8_t RoundKey[240];
|
||||||
|
uint8_t Iv[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
//internal function prototypes
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||||
|
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||||
|
|
||||||
|
typedef uint8_t state_t[4][4];
|
||||||
|
|
||||||
|
static const uint8_t sbox[256] = {
|
||||||
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||||
|
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||||
|
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||||
|
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||||
|
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||||
|
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||||
|
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||||
|
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||||
|
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
|
||||||
|
|
||||||
|
static const uint8_t rsbox[256] = {
|
||||||
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
|
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||||
|
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||||
|
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||||
|
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||||
|
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||||
|
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||||
|
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||||
|
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||||
|
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||||
|
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||||
|
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||||
|
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||||
|
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
|
||||||
|
|
||||||
|
static const uint8_t Rcon[11] = {
|
||||||
|
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||||
|
|
||||||
|
#define getSBoxValue(num) (sbox[(num)])
|
||||||
|
|
||||||
|
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
|
||||||
|
{
|
||||||
|
unsigned i, j, k;
|
||||||
|
uint8_t tempa[4]; // Used for the column/row operations
|
||||||
|
|
||||||
|
// The first round key is the key itself.
|
||||||
|
for (i = 0; i < Nk; ++i)
|
||||||
|
{
|
||||||
|
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||||
|
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||||
|
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||||
|
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
// All other round keys are found from the previous round keys.
|
||||||
|
for (i = Nk; i < Nb * (Nr + 1); ++i)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
k = (i - 1) * 4;
|
||||||
|
tempa[0]=RoundKey[k + 0];
|
||||||
|
tempa[1]=RoundKey[k + 1];
|
||||||
|
tempa[2]=RoundKey[k + 2];
|
||||||
|
tempa[3]=RoundKey[k + 3];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % Nk == 0)
|
||||||
|
{
|
||||||
|
// This function shifts the 4 bytes in a word to the left once.
|
||||||
|
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||||
|
|
||||||
|
// Function RotWord()
|
||||||
|
{
|
||||||
|
const uint8_t u8tmp = tempa[0];
|
||||||
|
tempa[0] = tempa[1];
|
||||||
|
tempa[1] = tempa[2];
|
||||||
|
tempa[2] = tempa[3];
|
||||||
|
tempa[3] = u8tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubWord() is a function that takes a four-byte input word and
|
||||||
|
// applies the S-box to each of the four bytes to produce an output word.
|
||||||
|
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempa[0] = tempa[0] ^ Rcon[i/Nk];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Nk == 8) //only run if using AES256 (Nk == 8)
|
||||||
|
{
|
||||||
|
if (i % Nk == 4)
|
||||||
|
{
|
||||||
|
// Function Subword()
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j = i * 4; k=(i - Nk) * 4;
|
||||||
|
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||||
|
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||||
|
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||||
|
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//input bit array, return output as up to a 64-bit value
|
||||||
|
uint64_t convert_bits_into_output_ta(uint8_t * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint64_t output = 0;
|
||||||
|
for(i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
output <<= 1;
|
||||||
|
output |= (uint64_t)(input[i] & 1);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
//take x amount of bits and pack into len amount of bytes (symmetrical)
|
||||||
|
void pack_bit_array_into_byte_array_ta (uint8_t * input, uint8_t * output, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
output[i] = (uint8_t)convert_bits_into_output_ta(&input[i*8], 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
//take len amount of bytes and unpack back into a bit array
|
||||||
|
void unpack_byte_array_into_bit_array_ta (uint8_t * input, uint8_t * output, int len)
|
||||||
|
{
|
||||||
|
int i = 0, k = 0;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
output[k++] = (input[i] >> 7) & 1;
|
||||||
|
output[k++] = (input[i] >> 6) & 1;
|
||||||
|
output[k++] = (input[i] >> 5) & 1;
|
||||||
|
output[k++] = (input[i] >> 4) & 1;
|
||||||
|
output[k++] = (input[i] >> 3) & 1;
|
||||||
|
output[k++] = (input[i] >> 2) & 1;
|
||||||
|
output[k++] = (input[i] >> 1) & 1;
|
||||||
|
output[k++] = (input[i] >> 0) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
}
|
||||||
|
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
|
||||||
|
{
|
||||||
|
memcpy (ctx->Iv, iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t i,j;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to left
|
||||||
|
temp = (*state)[0][1];
|
||||||
|
(*state)[0][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[3][1];
|
||||||
|
(*state)[3][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to left
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to left
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t xtime(uint8_t x)
|
||||||
|
{
|
||||||
|
return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t Tmp, Tm, t;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
t = (*state)[i][0];
|
||||||
|
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
|
||||||
|
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
|
||||||
|
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Multiply(x, y) \
|
||||||
|
( ((y & 1) * x) ^ \
|
||||||
|
((y>>1 & 1) * xtime(x)) ^ \
|
||||||
|
((y>>2 & 1) * xtime(xtime(x))) ^ \
|
||||||
|
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||||
|
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
|
||||||
|
|
||||||
|
|
||||||
|
#define getSBoxInvert(num) (rsbox[(num)])
|
||||||
|
|
||||||
|
static void InvMixColumns(state_t* state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8_t a, b, c, d;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
a = (*state)[i][0];
|
||||||
|
b = (*state)[i][1];
|
||||||
|
c = (*state)[i][2];
|
||||||
|
d = (*state)[i][3];
|
||||||
|
|
||||||
|
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||||
|
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||||
|
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||||
|
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvSubBytes(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; ++j)
|
||||||
|
{
|
||||||
|
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvShiftRows(state_t* state)
|
||||||
|
{
|
||||||
|
uint8_t temp;
|
||||||
|
|
||||||
|
// Rotate first row 1 columns to right
|
||||||
|
temp = (*state)[3][1];
|
||||||
|
(*state)[3][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[0][1];
|
||||||
|
(*state)[0][1] = temp;
|
||||||
|
|
||||||
|
// Rotate second row 2 columns to right
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
// Rotate third row 3 columns to right
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cipher is the main function that encrypts the PlainText,
|
||||||
|
// or produces a keystream, depending on application.
|
||||||
|
static void Cipher(state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(0, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr rounds are executed in the loop below.
|
||||||
|
// Last one without MixColumns()
|
||||||
|
for (round = 1; ; ++round)
|
||||||
|
{
|
||||||
|
SubBytes(state);
|
||||||
|
ShiftRows(state);
|
||||||
|
if (round == Nr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MixColumns(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
}
|
||||||
|
// Add round key to last round
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvCipher(state_t* state, const uint8_t* RoundKey)
|
||||||
|
{
|
||||||
|
uint8_t round = 0;
|
||||||
|
|
||||||
|
// Add the First round key to the state before starting the rounds.
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
|
||||||
|
// There will be Nr rounds.
|
||||||
|
// The first Nr-1 rounds are identical.
|
||||||
|
// These Nr rounds are executed in the loop below.
|
||||||
|
// Last one without InvMixColumn()
|
||||||
|
for (round = (Nr - 1); ; --round)
|
||||||
|
{
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(round, state, RoundKey);
|
||||||
|
if (round == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
InvMixColumns(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||||
|
{
|
||||||
|
// The next function call decrypts the PlainText with the Key using AES algorithm.
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < AES_BLOCKLEN; ++i)
|
||||||
|
{
|
||||||
|
buf[i] ^= Iv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t *Iv = ctx->Iv;
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
XorWithIv(buf, Iv);
|
||||||
|
Cipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
Iv = buf;
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
/* store Iv in ctx for next call */
|
||||||
|
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t storeNextIv[AES_BLOCKLEN];
|
||||||
|
for (i = 0; i < length; i += AES_BLOCKLEN)
|
||||||
|
{
|
||||||
|
memcpy(storeNextIv, buf, AES_BLOCKLEN);
|
||||||
|
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||||
|
XorWithIv(buf, ctx->Iv);
|
||||||
|
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
|
||||||
|
buf += AES_BLOCKLEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
|
||||||
|
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
|
||||||
|
{
|
||||||
|
uint8_t buffer[AES_BLOCKLEN];
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
int bi;
|
||||||
|
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
|
||||||
|
{
|
||||||
|
if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||||
|
Cipher((state_t*)buffer,ctx->RoundKey);
|
||||||
|
|
||||||
|
/* Increment Iv and handle overflow */
|
||||||
|
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
|
||||||
|
{
|
||||||
|
/* inc will overflow */
|
||||||
|
if (ctx->Iv[bi] == 255)
|
||||||
|
{
|
||||||
|
ctx->Iv[bi] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ctx->Iv[bi] += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bi = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = (buf[i] ^ buffer[bi]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-wise output of AES OFB Keystream
|
||||||
|
//input iv is a 16-byte uint8_t array of initialization vector
|
||||||
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
//input type is the type/key len of AES required (0-128, 1-192, 2-256)
|
||||||
|
//input nblocks is the number of rounds of 16-byte keystream output blocks requried
|
||||||
|
//output is a uint8_t bytewise array, each round filled with 16-bytes from aes keystream output
|
||||||
|
void aes_ofb_keystream_output (uint8_t * iv, uint8_t * key, uint8_t * output, int type, int nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
uint8_t input_register[16]; //OFB Input Register
|
||||||
|
memset (input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//load first round of input_register with received IV (OFB First Input Register)
|
||||||
|
memcpy (input_register, iv, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//initialize the key variable for the Cipher function
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
//execute the cipher function, and copy ciphered input_register to output for required number of rounds
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
Cipher((state_t*)input_register, ctx.RoundKey); //input_register is returned as output, and is put back in as object feedback
|
||||||
|
memcpy (output+(i*16), input_register, 16*sizeof(uint8_t) ); //copy ciphered input_register to output
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-wise AES CFB (Cipher Feedback) Payload operating in 128-bit block mode
|
||||||
|
//input in is a uint8_t bytewise array,is the input to be ciphered (encrypted or decrypted)
|
||||||
|
//input iv is a 16-byte uint8_t array of initialization vector
|
||||||
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
//input type is the type/key len of AES required (0-128, 1-192, 2-256)
|
||||||
|
//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
|
||||||
|
//output out is a uint8_t bytewise array, each round filled with 16-bytes of cfb ciphered output (encrypted or decrypted)
|
||||||
|
//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
|
||||||
|
void aes_cfb_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
uint8_t input_register[16]; //Input Register
|
||||||
|
memset (input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//load first round of input_register with received IV (CFB First Input Register)
|
||||||
|
memcpy (input_register, iv, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//initialize the key variable for the Cipher function
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
//execute the cipher function, and copy ciphered input_register to output for required number of rounds
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//the cipher is always run in the foward, or encryption mode
|
||||||
|
Cipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
|
||||||
|
//xor the current input 'in' to the current state of the input_register for cipher feedback
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
input_register[j] ^= in[j+(i*16)];
|
||||||
|
|
||||||
|
//copy ciphered/xor'd input_register to output 'out'
|
||||||
|
memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//if running in decryption mode, we feed in the next round of input
|
||||||
|
if (!de)
|
||||||
|
memcpy(input_register, in+(i*16), 16*sizeof(uint8_t));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-wise AES CBC (Cipher Block Chaining) //Yeah, I know this already exists, but wanted a custom convenience wrapper version
|
||||||
|
//input in is a uint8_t bytewise array,is the input to be ciphered (encrypted or decrypted)
|
||||||
|
//input iv is a 16-byte uint8_t array of initialization vector
|
||||||
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
//input type is the type/key len of AES required (0-128, 1-192, 2-256)
|
||||||
|
//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
|
||||||
|
//output out is a uint8_t bytewise array, each round filled with 16-bytes of cfb ciphered output (encrypted or decrypted)
|
||||||
|
//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
|
||||||
|
void aes_cbc_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks, int de)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
uint8_t input_register[16]; //Input Register
|
||||||
|
memset (input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//load first round of input_register accordingly
|
||||||
|
if (de)
|
||||||
|
memcpy (input_register, iv, 16*sizeof(uint8_t) );
|
||||||
|
else memcpy (input_register, in, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//initialize the key variable for the Cipher function
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//run encryption or decryption depending on de value
|
||||||
|
if (de) //encrypt
|
||||||
|
{
|
||||||
|
|
||||||
|
//xor the current input 'in' pt to the current state of the input_register for cbc feedback
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
input_register[j] ^= in[j+(i*16)];
|
||||||
|
|
||||||
|
Cipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
|
||||||
|
//copy ciphered input_register to output 'out'
|
||||||
|
memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else //decrypt
|
||||||
|
{
|
||||||
|
|
||||||
|
InvCipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
|
||||||
|
//copy ciphered input_register to output 'out'
|
||||||
|
memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//xor the current output by IV, or by last received CT
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
out[j] ^= iv[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
out[j+(i*16)] ^= in[j+((i-1)*16)];
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy in next segment for input_register (if not last)
|
||||||
|
if (i < nblocks)
|
||||||
|
memcpy(input_register, in+((i+1)*16), 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-wise AES CBC_MAC (Cipher Block Chaining Message Authentication) //This is slightly different than above, no IV is present,
|
||||||
|
//but if iv is desireable, it will need to be pre-XOR'd with the first plaintext input block by the calling function
|
||||||
|
//input in is a uint8_t bytewise array, is the input to be ciphered.
|
||||||
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
//input type is the type/key len of AES required (0-128, 1-192, 2-256)
|
||||||
|
//input nblocks is the number of rounds of 16-byte payload blocks requried (last block will need padding if not flush)
|
||||||
|
//output out is a uint8_t bytewise array, with only the final round output as the MAC octets
|
||||||
|
//NOTE: When doing a cbc_mac, you should only run it in the forward (encryption) mode to get the mac bytes
|
||||||
|
void aes_cbc_mac_generator (uint8_t * key, uint8_t * in, uint8_t * out, int type, int nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i, j;
|
||||||
|
uint8_t input_register[16]; //Input Register
|
||||||
|
memset (input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//initialize the key variable for the Cipher function
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
//
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//xor the current input 'in' pt to the current state of the input_register for cbc feedback
|
||||||
|
//if this is the first iteration, this will load the first round plain text instead
|
||||||
|
for (j = 0; j < 16; j++)
|
||||||
|
input_register[j] ^= in[j+((i+0)*16)];
|
||||||
|
|
||||||
|
Cipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
|
||||||
|
//debug, load out all intermediate output register values
|
||||||
|
// memcpy (out+(i*16), input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy final ciphered input_register to output 'out', user will determine how many bytes of output they want for MAC
|
||||||
|
memcpy (out, input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//byte-wise output of AES ECB Ciphering/Deciphering
|
||||||
|
//input is uint8_t byte-wise (16-bytes) data to be ciphered or deciphered
|
||||||
|
//input key is up to 32-byte uint8_t array of key value
|
||||||
|
//input type is the type/len of AES required (0-128, 1-192, 2-256)
|
||||||
|
//output is a uint8_t bytewise array of ciphered or deciphered input
|
||||||
|
//de is a bit-flag signalling to run Cipher (encrypt) on 1, or InvCipher (decrypt) on 0
|
||||||
|
void aes_ecb_bytewise_payload_crypt (uint8_t * input, uint8_t * key, uint8_t * output, int type, int de)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t input_register[16]; //ECB Input Register
|
||||||
|
memset (input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//load input_register with received input (ECB Payload)
|
||||||
|
memcpy (input_register, input, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
//initialize the key variable for the Cipher function
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
|
||||||
|
//run encryption or decryption depending on de value
|
||||||
|
if (de) //encrypt
|
||||||
|
Cipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
else //decrypt
|
||||||
|
InvCipher((state_t*)input_register, ctx.RoundKey);
|
||||||
|
|
||||||
|
//copy ciphered/deciphered input_register to output
|
||||||
|
memcpy (output, input_register, 16*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//symmetrical ctr mode payload encryption and decryption
|
||||||
|
void aes_ctr_bitwise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//init and set the iv and key variables
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
memset (ctx.Iv, 0, 16*sizeof(uint8_t));
|
||||||
|
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
memcpy (ctx.Iv, iv, AES_BLOCKLEN);
|
||||||
|
|
||||||
|
//pack input bit-wise payload to byte array
|
||||||
|
uint8_t payload_bytes[16];
|
||||||
|
memset (payload_bytes, 0, sizeof(payload_bytes));
|
||||||
|
pack_bit_array_into_byte_array_ta (payload, payload_bytes, 16);
|
||||||
|
|
||||||
|
//pass to internal CTR handler for payload
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, payload_bytes, 16);
|
||||||
|
|
||||||
|
//unpack output bytes back to bits
|
||||||
|
unpack_byte_array_into_bit_array_ta(payload_bytes, payload, 16);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//symmetrical ctr mode payload encryption and decryption
|
||||||
|
void aes_ctr_bytewise_payload_crypt (uint8_t * iv, uint8_t * key, uint8_t * payload, int type)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Set values specific to type (128/192/256)
|
||||||
|
if (type == 0) //128
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 4;
|
||||||
|
Nr = 10;
|
||||||
|
}
|
||||||
|
else if (type == 1) //192
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 6;
|
||||||
|
Nr = 12;
|
||||||
|
}
|
||||||
|
else //if (type == 2) //256
|
||||||
|
{
|
||||||
|
Nb = 4;
|
||||||
|
Nk = 8;
|
||||||
|
Nr = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
|
||||||
|
//init and set the iv and key variables
|
||||||
|
memset (ctx.RoundKey, 0, 240*sizeof(uint8_t));
|
||||||
|
memset (ctx.Iv, 0, 16*sizeof(uint8_t));
|
||||||
|
|
||||||
|
KeyExpansion(ctx.RoundKey, key);
|
||||||
|
memcpy (ctx.Iv, iv, AES_BLOCKLEN);
|
||||||
|
|
||||||
|
//pass to internal CTR handler for payload
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, payload, 16);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
832
src/crypt-des.c
Normal file
832
src/crypt-des.c
Normal file
@@ -0,0 +1,832 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* des.c Crypthings
|
||||||
|
* DES Alg
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
//NOTE: The SLUT boxes are S boxes with additional calculations so we don't have
|
||||||
|
//to manually sort out row and column values and can cut down on operations
|
||||||
|
|
||||||
|
uint8_t SLUT1[64] = {
|
||||||
|
0xE0,0x00,0x40,0xF0,0xD0,0x70,0x10,0x40,
|
||||||
|
0x20,0xE0,0xF0,0x20,0xB0,0xD0,0x80,0x10,
|
||||||
|
0x30,0xA0,0xA0,0x60,0x60,0xC0,0xC0,0xB0,
|
||||||
|
0x50,0x90,0x90,0x50,0x00,0x30,0x70,0x80,
|
||||||
|
0x40,0xF0,0x10,0xC0,0xE0,0x80,0x80,0x20,
|
||||||
|
0xD0,0x40,0x60,0x90,0x20,0x10,0xB0,0x70,
|
||||||
|
0xF0,0x50,0xC0,0xB0,0x90,0x30,0x70,0xE0,
|
||||||
|
0x30,0xA0,0xA0,0x00,0x50,0x60,0x00,0xD0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT2[64] = {
|
||||||
|
0x0F,0x03,0x01,0x0D,0x08,0x04,0x0E,0x07,
|
||||||
|
0x06,0x0F,0x0B,0x02,0x03,0x08,0x04,0x0E,
|
||||||
|
0x09,0x0C,0x07,0x00,0x02,0x01,0x0D,0x0A,
|
||||||
|
0x0C,0x06,0x00,0x09,0x05,0x0B,0x0A,0x05,
|
||||||
|
0x00,0x0D,0x0E,0x08,0x07,0x0A,0x0B,0x01,
|
||||||
|
0x0A,0x03,0x04,0x0F,0x0D,0x04,0x01,0x02,
|
||||||
|
0x05,0x0B,0x08,0x06,0x0C,0x07,0x06,0x0C,
|
||||||
|
0x09,0x00,0x03,0x05,0x02,0x0E,0x0F,0x09
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT3[64] = {
|
||||||
|
0xA0,0xD0,0x00,0x70,0x90,0x00,0xE0,0x90,
|
||||||
|
0x60,0x30,0x30,0x40,0xF0,0x60,0x50,0xA0,
|
||||||
|
0x10,0x20,0xD0,0x80,0xC0,0x50,0x70,0xE0,
|
||||||
|
0xB0,0xC0,0x40,0xB0,0x20,0xF0,0x80,0x10,
|
||||||
|
0xD0,0x10,0x60,0xA0,0x40,0xD0,0x90,0x00,
|
||||||
|
0x80,0x60,0xF0,0x90,0x30,0x80,0x00,0x70,
|
||||||
|
0xB0,0x40,0x10,0xF0,0x20,0xE0,0xC0,0x30,
|
||||||
|
0x50,0xB0,0xA0,0x50,0xE0,0x20,0x70,0xC0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT4[64] = {
|
||||||
|
0x07,0x0D,0x0D,0x08,0x0E,0x0B,0x03,0x05,
|
||||||
|
0x00,0x06,0x06,0x0F,0x09,0x00,0x0A,0x03,
|
||||||
|
0x01,0x04,0x02,0x07,0x08,0x02,0x05,0x0C,
|
||||||
|
0x0B,0x01,0x0C,0x0A,0x04,0x0E,0x0F,0x09,
|
||||||
|
0x0A,0x03,0x06,0x0F,0x09,0x00,0x00,0x06,
|
||||||
|
0x0C,0x0A,0x0B,0x01,0x07,0x0D,0x0D,0x08,
|
||||||
|
0x0F,0x09,0x01,0x04,0x03,0x05,0x0E,0x0B,
|
||||||
|
0x05,0x0C,0x02,0x07,0x08,0x02,0x04,0x0E
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT5[64] = {
|
||||||
|
0x20,0xE0,0xC0,0xB0,0x40,0x20,0x10,0xC0,
|
||||||
|
0x70,0x40,0xA0,0x70,0xB0,0xD0,0x60,0x10,
|
||||||
|
0x80,0x50,0x50,0x00,0x30,0xF0,0xF0,0xA0,
|
||||||
|
0xD0,0x30,0x00,0x90,0xE0,0x80,0x90,0x60,
|
||||||
|
0x40,0xB0,0x20,0x80,0x10,0xC0,0xB0,0x70,
|
||||||
|
0xA0,0x10,0xD0,0xE0,0x70,0x20,0x80,0xD0,
|
||||||
|
0xF0,0x60,0x90,0xF0,0xC0,0x00,0x50,0x90,
|
||||||
|
0x60,0xA0,0x30,0x40,0x00,0x50,0xE0,0x30
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT6[64] = {
|
||||||
|
0x0C,0x0A,0x01,0x0F,0x0A,0x04,0x0F,0x02,
|
||||||
|
0x09,0x07,0x02,0x0C,0x06,0x09,0x08,0x05,
|
||||||
|
0x00,0x06,0x0D,0x01,0x03,0x0D,0x04,0x0E,
|
||||||
|
0x0E,0x00,0x07,0x0B,0x05,0x03,0x0B,0x08,
|
||||||
|
0x09,0x04,0x0E,0x03,0x0F,0x02,0x05,0x0C,
|
||||||
|
0x02,0x09,0x08,0x05,0x0C,0x0F,0x03,0x0A,
|
||||||
|
0x07,0x0B,0x00,0x0E,0x04,0x01,0x0A,0x07,
|
||||||
|
0x01,0x06,0x0D,0x00,0x0B,0x08,0x06,0x0D
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT7[64] = {
|
||||||
|
0x40,0xD0,0xB0,0x00,0x20,0xB0,0xE0,0x70,
|
||||||
|
0xF0,0x40,0x00,0x90,0x80,0x10,0xD0,0xA0,
|
||||||
|
0x30,0xE0,0xC0,0x30,0x90,0x50,0x70,0xC0,
|
||||||
|
0x50,0x20,0xA0,0xF0,0x60,0x80,0x10,0x60,
|
||||||
|
0x10,0x60,0x40,0xB0,0xB0,0xD0,0xD0,0x80,
|
||||||
|
0xC0,0x10,0x30,0x40,0x70,0xA0,0xE0,0x70,
|
||||||
|
0xA0,0x90,0xF0,0x50,0x60,0x00,0x80,0xF0,
|
||||||
|
0x00,0xE0,0x50,0x20,0x90,0x30,0x20,0xC0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t SLUT8[64] = {
|
||||||
|
0x0D,0x01,0x02,0x0F,0x08,0x0D,0x04,0x08,
|
||||||
|
0x06,0x0A,0x0F,0x03,0x0B,0x07,0x01,0x04,
|
||||||
|
0x0A,0x0C,0x09,0x05,0x03,0x06,0x0E,0x0B,
|
||||||
|
0x05,0x00,0x00,0x0E,0x0C,0x09,0x07,0x02,
|
||||||
|
0x07,0x02,0x0B,0x01,0x04,0x0E,0x01,0x07,
|
||||||
|
0x09,0x04,0x0C,0x0A,0x0E,0x08,0x02,0x0D,
|
||||||
|
0x00,0x0F,0x06,0x0C,0x0A,0x09,0x0D,0x00,
|
||||||
|
0x0F,0x03,0x03,0x05,0x05,0x06,0x08,0x0B
|
||||||
|
};
|
||||||
|
|
||||||
|
//initial permutation IP (on input)
|
||||||
|
uint8_t initial_register_permutation[64] = {
|
||||||
|
58, 50, 42, 34, 26, 18, 10, 2,
|
||||||
|
60, 52, 44, 36, 28, 20, 12, 4,
|
||||||
|
62, 54, 46, 38, 30, 22, 14, 6,
|
||||||
|
64, 56, 48, 40, 32, 24, 16, 8,
|
||||||
|
57, 49, 41, 33, 25, 17, 9, 1,
|
||||||
|
59, 51, 43, 35, 27, 19, 11, 3,
|
||||||
|
61, 53, 45, 37, 29, 21, 13, 5,
|
||||||
|
63, 55, 47, 39, 31, 23, 15, 7};
|
||||||
|
|
||||||
|
//D-Box Expansion (sometimes noted as E BIT-SELECTION TABLE)
|
||||||
|
uint8_t message_expansion[48] = {
|
||||||
|
32, 1, 2, 3, 4, 5,
|
||||||
|
4, 5, 6, 7, 8, 9,
|
||||||
|
8, 9, 10, 11, 12, 13,
|
||||||
|
12, 13, 14, 15, 16, 17,
|
||||||
|
16, 17, 18, 19, 20, 21,
|
||||||
|
20, 21, 22, 23, 24, 25,
|
||||||
|
24, 25, 26, 27, 28, 29,
|
||||||
|
28, 29, 30, 31, 32, 1};
|
||||||
|
|
||||||
|
// (sometimes noted as simply 'P')
|
||||||
|
uint8_t right_half_permutation[32] = {
|
||||||
|
16, 7, 20, 21,
|
||||||
|
29, 12, 28, 17,
|
||||||
|
1, 15, 23, 26,
|
||||||
|
5, 18, 31, 10,
|
||||||
|
2, 8, 24, 14,
|
||||||
|
32, 27, 3, 9,
|
||||||
|
19, 13, 30, 6,
|
||||||
|
22, 11, 4, 25};
|
||||||
|
|
||||||
|
//inverse initial PI, a.k.a. final permutation (on output)
|
||||||
|
uint8_t final_register_permutation[64] = {
|
||||||
|
40, 8, 48, 16, 56, 24, 64, 32,
|
||||||
|
39, 7, 47, 15, 55, 23, 63, 31,
|
||||||
|
38, 6, 46, 14, 54, 22, 62, 30,
|
||||||
|
37, 5, 45, 13, 53, 21, 61, 29,
|
||||||
|
36, 4, 44, 12, 52, 20, 60, 28,
|
||||||
|
35, 3, 43, 11, 51, 19, 59, 27,
|
||||||
|
34, 2, 42, 10, 50, 18, 58, 26,
|
||||||
|
33, 1, 41, 9, 49, 17, 57, 25};
|
||||||
|
|
||||||
|
//initial key permutation
|
||||||
|
uint8_t pc1_key_permutation[56] = {
|
||||||
|
57, 49, 41, 33, 25, 17, 9,
|
||||||
|
1, 58, 50, 42, 34, 26, 18,
|
||||||
|
10, 2, 59, 51, 43, 35, 27,
|
||||||
|
19, 11, 3, 60, 52, 44, 36,
|
||||||
|
63, 55, 47, 39, 31, 23, 15,
|
||||||
|
7, 62, 54, 46, 38, 30, 22,
|
||||||
|
14, 6, 61, 53, 45, 37, 29,
|
||||||
|
21, 13, 5, 28, 20, 12, 4};
|
||||||
|
|
||||||
|
//sub c and d key permutation
|
||||||
|
uint8_t pc2_key_permutation[48] = {
|
||||||
|
//c bits
|
||||||
|
14,17,11,24,1,5,
|
||||||
|
3,28,15,6,21,10,
|
||||||
|
23,19,12,4,26,8,
|
||||||
|
16,7,27,20,13,2,
|
||||||
|
//d bits (with -28 offset to simply/only have one permute function)
|
||||||
|
13,24,3,9,19,27,
|
||||||
|
2,12,23,17,5,20,
|
||||||
|
16,21,11,28,6,25,
|
||||||
|
18,14,22,8,1,4
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t key_shift_sizes[17] = {
|
||||||
|
1,
|
||||||
|
1, 1, 2, 2,
|
||||||
|
2, 2, 2, 2,
|
||||||
|
1, 2, 2, 2,
|
||||||
|
2, 2, 2, 1};
|
||||||
|
|
||||||
|
uint8_t key_shift_bytes[17] = {
|
||||||
|
0x80,
|
||||||
|
0x80, 0x80, 0xC0, 0xC0,
|
||||||
|
0xC0, 0xC0, 0xC0, 0xC0,
|
||||||
|
0x80, 0xC0, 0xC0, 0xC0,
|
||||||
|
0xC0, 0xC0, 0xC0, 0x80};
|
||||||
|
|
||||||
|
uint8_t key_shift_x[4] = {8,8,8,4};
|
||||||
|
|
||||||
|
uint8_t key_shift_y[4] = {1,2,3,0};
|
||||||
|
|
||||||
|
//input is byte-wise array, output is byte-wise array
|
||||||
|
void permute(uint8_t * input, uint8_t * output, uint8_t * table, uint8_t start, uint8_t end)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (uint8_t i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
uint8_t tdiv = (table[i] - 1) / 8;
|
||||||
|
uint8_t tmod = (table[i] - 1) % 8;
|
||||||
|
uint8_t idiv = i/8;
|
||||||
|
uint8_t imod = i%8;
|
||||||
|
|
||||||
|
//need a way to simplify or get rid of all these shifts
|
||||||
|
uint8_t bit = (((input[tdiv] & (0x80 >> tmod)) << tmod) >> imod);
|
||||||
|
output[idiv] |= bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void rotate_sub_keys(uint8_t * Kc, uint8_t * Kd, uint8_t shift_size, uint8_t shift_byte)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t sb1[4]; memset(sb1, 0, sizeof(sb1));
|
||||||
|
uint8_t sb2[4]; memset(sb2, 0, sizeof(sb2));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
sb1[i] = shift_byte & Kc[i];
|
||||||
|
sb2[i] = shift_byte & Kd[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t x = key_shift_x[i];
|
||||||
|
uint8_t y = key_shift_y[i];
|
||||||
|
|
||||||
|
Kc[i] <<= shift_size;
|
||||||
|
Kd[i] <<= shift_size;
|
||||||
|
|
||||||
|
Kc[i] |= (sb1[y] >> (x - shift_size));
|
||||||
|
Kd[i] |= (sb2[y] >> (x - shift_size));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void des_cipher (uint8_t * main_key, uint8_t * input_register, uint8_t * output_register, uint8_t de)
|
||||||
|
{
|
||||||
|
|
||||||
|
//starting and ending permutations
|
||||||
|
uint8_t initial_permutation[8]; memset(initial_permutation, 0, sizeof(initial_permutation));
|
||||||
|
uint8_t pre_end_permutation[8]; memset(pre_end_permutation, 0, sizeof(pre_end_permutation));
|
||||||
|
|
||||||
|
//intermediate left, right, and expansion/selection arrays
|
||||||
|
uint8_t left[4]; memset(left, 0, sizeof(left));
|
||||||
|
uint8_t right[4]; memset(right, 0, sizeof(right));
|
||||||
|
uint8_t rperm[4]; memset(rperm, 0, sizeof(rperm));
|
||||||
|
uint8_t exp[6]; memset(exp, 0, sizeof(exp));
|
||||||
|
uint8_t sel[4]; memset(sel, 0, sizeof(sel));
|
||||||
|
|
||||||
|
//key sets
|
||||||
|
uint8_t Ks[16][7]; memset(Ks, 0, sizeof(Ks));
|
||||||
|
uint8_t Kc[4]; memset(Kc, 0, sizeof(Kc));
|
||||||
|
uint8_t Kd[4]; memset(Kd, 0, sizeof(Kd));
|
||||||
|
|
||||||
|
//initial Ks permutation and shuffle to Kc and Kd
|
||||||
|
permute (main_key, Ks[0], pc1_key_permutation, 0, 56);
|
||||||
|
for (uint8_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
Kc[i] = Ks[0][i];
|
||||||
|
}
|
||||||
|
Kc[3] = Ks[0][3] & 0xF0;
|
||||||
|
for (uint8_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
Kd[i] = (Ks[0][i+3] & 0x0F) << 4;
|
||||||
|
Kd[i] |= (Ks[0][i+4] & 0xF0) >> 4;
|
||||||
|
}
|
||||||
|
Kd[3] = (Ks[0][6] & 0x0F) << 4;
|
||||||
|
|
||||||
|
//reset Ks
|
||||||
|
memset(Ks, 0, sizeof(Ks));
|
||||||
|
|
||||||
|
//create the 16 Ks rounds
|
||||||
|
for (uint8_t i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
uint8_t shift_size = key_shift_sizes[i+1];
|
||||||
|
uint8_t shift_byte = key_shift_bytes[i+1];
|
||||||
|
rotate_sub_keys(Kc, Kd, shift_size, shift_byte);
|
||||||
|
permute (Kc, Ks[i], pc2_key_permutation, 0, 24);
|
||||||
|
permute (Kd, Ks[i], pc2_key_permutation, 24, 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
//permute the input_register with the ip (initial_register_permutation) table
|
||||||
|
permute (input_register, initial_permutation, initial_register_permutation, 0, 64);
|
||||||
|
|
||||||
|
//copy the initial permutation to left and right half arrays
|
||||||
|
memcpy (left, initial_permutation+0, sizeof(left));
|
||||||
|
memcpy (right, initial_permutation+4, sizeof(right));
|
||||||
|
|
||||||
|
//16 fiestel rounds
|
||||||
|
for (uint8_t f = 0; f < 16; f++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//reset rperm and exp arrays
|
||||||
|
memset(rperm, 0, sizeof(rperm));
|
||||||
|
memset(exp, 0, sizeof(exp));
|
||||||
|
|
||||||
|
//expand right half from 32-bit to 48-bit
|
||||||
|
permute (right, exp, message_expansion, 0, 48);
|
||||||
|
|
||||||
|
//apply current iteration keyset to the expanded array (encryption cycles Ks forward, decryption goes in reverse)
|
||||||
|
if (de == 1)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
exp[i] ^= Ks[f][i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 6; i++)
|
||||||
|
exp[i] ^= Ks[15-f][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//extract 6 bits for each sbox swap from the expanded array
|
||||||
|
uint8_t e1 = exp[0] >> 2;
|
||||||
|
uint8_t e2 = ((exp[0] & 0x3) << 4) | (exp[1] >> 4);
|
||||||
|
uint8_t e3 = ((exp[1] & 0xF) << 2) | (exp[2] >> 6);
|
||||||
|
uint8_t e4 = exp[2] & 0x3F;
|
||||||
|
|
||||||
|
uint8_t e5 = exp[3] >> 2;
|
||||||
|
uint8_t e6 = ((exp[3] & 0x3) << 4) | (exp[4] >> 4);
|
||||||
|
uint8_t e7 = ((exp[4] & 0xF) << 2) | (exp[5] >> 6);
|
||||||
|
uint8_t e8 = exp[5] & 0x3F;
|
||||||
|
|
||||||
|
//select 32-bits of each 48-bit expansion via modified S Box Look Up Tables
|
||||||
|
//swap the 6 bits for 4 bits via SLUT tables and OR them together into a selection array
|
||||||
|
sel[0] = SLUT1[e1] | SLUT2[e2];
|
||||||
|
sel[1] = SLUT3[e3] | SLUT4[e4];
|
||||||
|
sel[2] = SLUT5[e5] | SLUT6[e6];
|
||||||
|
sel[3] = SLUT7[e7] | SLUT8[e8];
|
||||||
|
|
||||||
|
//permute the selected 32-bits into a new right half
|
||||||
|
permute (sel, rperm, right_half_permutation, 0, 32);
|
||||||
|
|
||||||
|
//xor new right half against left half
|
||||||
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
|
rperm[i] ^= left[i];
|
||||||
|
|
||||||
|
//swap old right half to left, set new right half to rperm
|
||||||
|
memcpy (left, right, sizeof(left));
|
||||||
|
memcpy (right, rperm, sizeof(right));
|
||||||
|
|
||||||
|
} //end fiestel rounds f
|
||||||
|
|
||||||
|
//combine right and left into the pre_end_permutation array
|
||||||
|
memcpy (pre_end_permutation+0, right, sizeof(right));
|
||||||
|
memcpy (pre_end_permutation+4, left, sizeof(left));
|
||||||
|
|
||||||
|
//carry out the final permuation to get the completed output_register for this cipher iteration
|
||||||
|
permute (pre_end_permutation, output_register, final_register_permutation, 0, 64);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void des56_ofb_keystream_output (uint8_t * main_key, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
|
||||||
|
memcpy(input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
//execute the des_cipher in output feedback mode
|
||||||
|
for (int16_t i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
//de should be 1 here for encryption mode
|
||||||
|
des_cipher(main_key, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input register
|
||||||
|
memcpy(ks_bytes+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//the des_cipher function is already ECB mode, this convenience wrapper is just available as a reminder to illustrate that point
|
||||||
|
void des56_ecb_payload_crypt (uint8_t * main_key, uint8_t * input_register, uint8_t * output_register, uint8_t de)
|
||||||
|
{
|
||||||
|
//de 1 for encryption mode, 0 for decryption mode
|
||||||
|
des_cipher(main_key, input_register, output_register, de);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in electronic codebook mode
|
||||||
|
void tdea_ecb_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * input, uint8_t * output, uint8_t de)
|
||||||
|
{
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the input to the input_register (make copy so we don't manipulate the calling functions copy)
|
||||||
|
memcpy(input_register, input, sizeof(input_register));
|
||||||
|
|
||||||
|
//For TDEA, the cipher alternates between encryption and decryption to the payload
|
||||||
|
//so, for example, K1 is run as de=1, K2 is run as de=0, and K3 is run as de=1,
|
||||||
|
//K1 and K3 will always use the same mode and K2 will be the opposite
|
||||||
|
|
||||||
|
//NOTE: If running ECB mode in decryption, make sure to send the keys in reverse order
|
||||||
|
//so that its K3, K2, and K1 for decryption, and K1, K2, K3 for encryption
|
||||||
|
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit
|
||||||
|
des_cipher(K2, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit back
|
||||||
|
des_cipher(K3, input_register, output_register, de);
|
||||||
|
|
||||||
|
//copy payload out
|
||||||
|
memcpy(output, output_register, sizeof(output_register)); //copy output_register to output
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in cipher block chain mode (64-bit)
|
||||||
|
//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
|
||||||
|
//if running in decryption mode, this will reverse the key bundle order from (K1, K2, K3) to (K3, K2, K1) on this end
|
||||||
|
void tdea_cbc_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * in, uint8_t * out, int16_t nblocks, uint8_t de)
|
||||||
|
{
|
||||||
|
|
||||||
|
int16_t i, j;
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//load first round of input_register accordingly
|
||||||
|
if (de)
|
||||||
|
memcpy (input_register, iv, sizeof(input_register)); //load the IV as first input_register if encrypting
|
||||||
|
else memcpy (input_register, in, sizeof(input_register)); //load first cipher text as input_register is decrypting
|
||||||
|
|
||||||
|
//run payload for number of payload nblocks required
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (de)
|
||||||
|
{
|
||||||
|
|
||||||
|
//xor the current input 'in' pt to the current state of the input_register for cbc feedback
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
input_register[j] ^= in[j+(i*8)];
|
||||||
|
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit
|
||||||
|
des_cipher(K2, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit back
|
||||||
|
des_cipher(K3, input_register, output_register, de);
|
||||||
|
memcpy (input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
|
||||||
|
//copy ciphered output_register to output 'out'
|
||||||
|
memcpy (out+(i*8), output_register, sizeof(output_register));
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
//K3
|
||||||
|
des_cipher(K3, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit
|
||||||
|
des_cipher(K2, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K1
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit back
|
||||||
|
des_cipher(K1, input_register, output_register, de);
|
||||||
|
memcpy (input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
|
||||||
|
//copy ciphered input_register to output 'out'
|
||||||
|
memcpy (out+(i*8), output_register, sizeof(output_register));
|
||||||
|
|
||||||
|
//xor the current output by IV, or by last received CT, depending on round
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
out[j] ^= iv[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
out[j+(i*8)] ^= in[j+((i-1)*8)];
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy in next segment for input_register (if not last)
|
||||||
|
if (i < nblocks)
|
||||||
|
memcpy(input_register, in+((i+1)*8), sizeof(input_register));
|
||||||
|
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in cipher block chain mode (64-bit)
|
||||||
|
//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
|
||||||
|
//only the last output_register is returned for the variable len MAC bytes, always run in encryption mode
|
||||||
|
//but if iv is desireable, it will need to be pre-XOR'd with the first plaintext input block by the calling function
|
||||||
|
void tdea_cbc_mac_generator (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * in, uint8_t * out, int16_t nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
int16_t i, j;
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//run payload for number of payload nblocks required
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//the cipher is always run in the foward, or encryption mode (1,0,1)
|
||||||
|
|
||||||
|
//xor the current input 'in' pt to the current state of the input_register for cbc feedback
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
input_register[j] ^= in[j+(i*8)];
|
||||||
|
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
des_cipher(K2, input_register, output_register, 0);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
des_cipher(K3, input_register, output_register, 1);
|
||||||
|
memcpy (input_register, output_register, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy ciphered output_register to output 'out'
|
||||||
|
//Since we only want the last output_register,
|
||||||
|
//this will overwrite the out until completion
|
||||||
|
memcpy (out, output_register, sizeof(output_register));
|
||||||
|
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in cihper feedback mode (64-bit)
|
||||||
|
//same as usual inputs (byte wise), also, if needing DES56, just feed the same key into K1, K2, and K3
|
||||||
|
void tdea_cfb_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * in, uint8_t * out, int16_t nblocks, uint8_t de)
|
||||||
|
{
|
||||||
|
|
||||||
|
int16_t i, j;
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
|
||||||
|
memcpy(input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
//execute the des_cipher in output feedback mode 3 times using each key and transferring output to input each time
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//the cipher is always run in the foward, or encryption mode (1,0,1)
|
||||||
|
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
des_cipher(K2, input_register, output_register, 0);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
des_cipher(K3, input_register, output_register, 1);
|
||||||
|
|
||||||
|
//xor the current input 'in' to the current state of the input_register for cipher feedback
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
output_register[j] ^= in[j+(i*8)];
|
||||||
|
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
|
||||||
|
//copy keystream out and reset
|
||||||
|
memcpy(out+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//if running in decryption mode, we feed in the next round of input
|
||||||
|
if (!de)
|
||||||
|
memcpy(input_register, in+(i*8), sizeof(input_register));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in IV counter mode (tested, working)
|
||||||
|
void tdea_ctr_payload_crypt (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * input, uint8_t * output, int16_t nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
int16_t i, j;
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the IV to the input_register (ctr mode will manipulate the IV, since it needs to keep a rolling counter
|
||||||
|
memcpy(input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
//execute the des_cipher in counter mode 3 times using each key and transferring output to input each time
|
||||||
|
//then the IV is iterated and fed back into the input_register to start the next nblocks loop
|
||||||
|
for (i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//CTR mode cipher should always run in the forward (encryption) mode
|
||||||
|
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, 1);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
des_cipher(K2, input_register, output_register, 0);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
des_cipher(K3, input_register, output_register, 1);
|
||||||
|
|
||||||
|
//set output at current pointer to the xor of input current pointer and the output_register
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
output[j+(i*8)] = input[j+(i*8)] ^ output_register[j];
|
||||||
|
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//increment the IV, and handle roll over (uint8_t will rollover to 0 after 0xFF)
|
||||||
|
for (j = 7; j >= 0; j--)
|
||||||
|
{
|
||||||
|
iv[j]++;
|
||||||
|
if (iv[j] == 0)
|
||||||
|
continue;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug IV iteration
|
||||||
|
// fprintf (stderr, "\n IV: ");
|
||||||
|
// for (j = 0; j < 8; j++)
|
||||||
|
// fprintf (stderr, "%02X", iv[j]);
|
||||||
|
|
||||||
|
//feed the new IV into the input register
|
||||||
|
memcpy (input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TDEA, or triple data encryption algorithm, or triple DES, in output feedback mode
|
||||||
|
void tdea_tofb_keystream_output (uint8_t * K1, uint8_t * K2, uint8_t * K3, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t nblocks)
|
||||||
|
{
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
|
||||||
|
memcpy(input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
//execute the des_cipher in output feedback mode 3 times using each key and transferring output to input each time
|
||||||
|
for (int16_t i = 0; i < nblocks; i++)
|
||||||
|
{
|
||||||
|
//K1
|
||||||
|
des_cipher(K1, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K2
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit
|
||||||
|
des_cipher(K2, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
|
||||||
|
//K3
|
||||||
|
de = (de ^ 1) & 1; //flip the de bit back
|
||||||
|
des_cipher(K3, input_register, output_register, de);
|
||||||
|
memcpy(input_register, output_register, sizeof(output_register)); //recycle output_register back into input_register
|
||||||
|
|
||||||
|
//copy keystream out and reset
|
||||||
|
memcpy(ks_bytes+(i*8), output_register, sizeof(output_register)); //copy output_register to ks_bytes + iteration offset of times 8
|
||||||
|
memset(output_register, 0, sizeof(output_register)); //reset output register
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//a linear feedback shift register with maximal taps on 64-bit values that can be run to any specified len,
|
||||||
|
//its input is a byte array of up to 8 bytes, and its output is same array packed with new LFSR value in it.
|
||||||
|
uint64_t lfsr_64_to_len_ca(uint8_t * iv, int16_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t lfsr = 0, bit = 0;
|
||||||
|
|
||||||
|
lfsr = ((uint64_t)iv[0] << 56ULL) + ((uint64_t)iv[1] << 48ULL) + ((uint64_t)iv[2] << 40ULL) + ((uint64_t)iv[3] << 32ULL) +
|
||||||
|
((uint64_t)iv[4] << 24ULL) + ((uint64_t)iv[5] << 16ULL) + ((uint64_t)iv[6] << 8ULL) + ((uint64_t)iv[7] << 0ULL);
|
||||||
|
|
||||||
|
memset (iv, 0, 8*sizeof(uint8_t));
|
||||||
|
|
||||||
|
for(int16_t cnt = 0; cnt < len; cnt++)
|
||||||
|
{
|
||||||
|
//63,61,45,37,27,14
|
||||||
|
// Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
|
||||||
|
bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
|
||||||
|
lfsr = (lfsr << 1) | bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < 8; i++)
|
||||||
|
iv[i] = (lfsr >> (56-(i*8))) & 0xFF;
|
||||||
|
|
||||||
|
// fprintf (stderr, "\n IV(%02d): ", len);
|
||||||
|
// for (int16_t i = 0; i < 8; i++)
|
||||||
|
// fprintf (stderr, "%02X", iv[i]);
|
||||||
|
|
||||||
|
return bit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void des56_ca_keystream_output (uint8_t * main_key, uint8_t * iv, uint8_t * ks_bytes, uint8_t de, int16_t ff, int16_t nbits)
|
||||||
|
{
|
||||||
|
|
||||||
|
//cipher input and output
|
||||||
|
uint8_t input_register[8]; memset(input_register, 0, sizeof(input_register));
|
||||||
|
uint8_t output_register[8]; memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
//copy the IV to the input_register (make copy so we don't manipulate the calling functions copy)
|
||||||
|
memcpy(input_register, iv, sizeof(input_register));
|
||||||
|
|
||||||
|
//fast forward the current input_register state
|
||||||
|
lfsr_64_to_len_ca(input_register, ff);
|
||||||
|
|
||||||
|
//execute the des_cipher in (CA) mode with 1-bit output
|
||||||
|
for (int16_t i = 0; i < nbits; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//de should be 1 here for encryption mode
|
||||||
|
des_cipher(main_key, input_register, output_register, de);
|
||||||
|
|
||||||
|
//keystream accumulation, shift current byte and append
|
||||||
|
//single bit from current output register's most significant bit
|
||||||
|
ks_bytes[i/8] <<= 1;
|
||||||
|
ks_bytes[i/8] |= ((output_register[0] >> 7) & 1);
|
||||||
|
|
||||||
|
//advance the input_register with the lfsr 1 time
|
||||||
|
lfsr_64_to_len_ca(input_register, 1);
|
||||||
|
|
||||||
|
//reset output register
|
||||||
|
memset(output_register, 0, sizeof(output_register));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf (stderr, "\n IR: ");
|
||||||
|
// for (int16_t i = 0; i < 8; i++)
|
||||||
|
// fprintf (stderr, "%02X", input_register[i]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//transitional function mainly to load key and iv into an array
|
||||||
|
void des_multi_keystream_output (unsigned long long int mi, unsigned long long int key_ulli, uint8_t * output, int type, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint8_t iv[8]; memset (iv, 0, sizeof(iv));
|
||||||
|
uint8_t key[8]; memset(key, 0, sizeof(key));
|
||||||
|
|
||||||
|
//convert unsinged long long int values into array values
|
||||||
|
for (i = 7; i >= 0; i--)
|
||||||
|
iv[7-i] = (mi >> (8*i)) & 0xFF;
|
||||||
|
|
||||||
|
for (i = 7; i >= 0; i--)
|
||||||
|
key[7-i] = (key_ulli >> (8*i)) & 0xFF;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n IV: ");
|
||||||
|
// for (i = 0; i < 8; i++)
|
||||||
|
// fprintf (stderr, "%02X", iv[i]);
|
||||||
|
// fprintf (stderr, "\n Key: ");
|
||||||
|
// for (i = 0; i < 8; i++)
|
||||||
|
// fprintf (stderr, "%02X", key[i]);
|
||||||
|
|
||||||
|
//types: 1 = DES56 OFB; 2 = DES56 CA (XL)
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
des56_ca_keystream_output(key, iv, output, 1, 110+696, 1704);
|
||||||
|
else des56_ca_keystream_output(key, iv, output, 1, 110+000, 1704);
|
||||||
|
}
|
||||||
|
else des56_ofb_keystream_output(key, iv, output, 1, len);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//transitional function mainly to load iv into an array
|
||||||
|
void tdea_multi_keystream_output (unsigned long long int mi, uint8_t * key, uint8_t * output, int type, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint8_t iv[8]; memset (iv, 0, sizeof(iv));
|
||||||
|
|
||||||
|
//convert unsinged long long int values into array values
|
||||||
|
for (i = 7; i >= 0; i--)
|
||||||
|
iv[7-i] = (mi >> (8*i)) & 0xFF;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n IV: ");
|
||||||
|
// for (i = 0; i < 8; i++)
|
||||||
|
// fprintf (stderr, "%02X", iv[i]);
|
||||||
|
|
||||||
|
//type 1 = TDEA TOFB //TODO: Add more types like 2DES?
|
||||||
|
if (type == 1)
|
||||||
|
tdea_tofb_keystream_output(key, key+8, key+16, iv, output, 1, len);
|
||||||
|
else tdea_tofb_keystream_output(key, key+8, key+16, iv, output, 1, len);
|
||||||
|
|
||||||
|
}
|
||||||
126
src/crypt-etc.c
Normal file
126
src/crypt-etc.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
void ken_dmr_scrambler_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
SLOT 1 Protected LC FLCO=0x00 FID=0x20 <--this link appears to indicate scrambler usage from Kenwood on DMR
|
||||||
|
DMR PDU Payload [80][20][40][00][00][01][00][00][01] SB: 00000000000 - 000;
|
||||||
|
|
||||||
|
SLOT 1 TGT=1 SRC=1 FLCO=0x00 FID=0x00 SVC=0x00 Group Call <--different call, no scrambler from same Kenwood Radio
|
||||||
|
DMR PDU Payload [00][00][00][00][00][01][00][00][01]
|
||||||
|
|
||||||
|
For This, we could possible transition this to not be enforced
|
||||||
|
since we may have a positive indicator in link control,
|
||||||
|
but needs further samples and validation
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lfsr = 0, bit = 0;
|
||||||
|
sscanf (input, "%d", &lfsr);
|
||||||
|
fprintf (stderr,"DMR Kenwood 15-bit Scrambler Key %05d with Forced Application\n", lfsr);
|
||||||
|
|
||||||
|
for (int i = 0; i < 882; i++)
|
||||||
|
{
|
||||||
|
state->static_ks_bits[0][i] = lfsr & 0x1;
|
||||||
|
state->static_ks_bits[1][i] = lfsr & 0x1;
|
||||||
|
bit = ( (lfsr >> 1) ^ (lfsr >> 0) ) & 1;
|
||||||
|
lfsr = ( (lfsr >> 1 ) | (bit << 14) );
|
||||||
|
}
|
||||||
|
|
||||||
|
state->ken_sc = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void anytone_bp_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
uint16_t key = 0;
|
||||||
|
uint16_t kperm = 0;
|
||||||
|
|
||||||
|
sscanf (input, "%hX", &key);
|
||||||
|
key &= 0xFFFF; //truncate to 16-bits
|
||||||
|
|
||||||
|
//calculate key permutation using simple operations
|
||||||
|
uint8_t nib1, nib2, nib3, nib4;
|
||||||
|
|
||||||
|
//nib 1 and 3 are simple inversions
|
||||||
|
nib1 = ~(key >> 12) & 0xF;
|
||||||
|
nib3 = ~(key >> 4) & 0xF;
|
||||||
|
|
||||||
|
//nib 2 and 4 are +8 and mod 16 (& 0xF)
|
||||||
|
nib2 = (((key >> 8) & 0xF) + 8) % 16;
|
||||||
|
nib4 = (((key >> 0) & 0xF) + 8) % 16;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "{%01X, %01X, %01X, %01X}", nib1, nib2, nib3, nib4);
|
||||||
|
|
||||||
|
kperm = nib1;
|
||||||
|
kperm <<= 4;
|
||||||
|
kperm |= nib2;
|
||||||
|
kperm <<= 4;
|
||||||
|
kperm |= nib3;
|
||||||
|
kperm <<= 4;
|
||||||
|
kperm |= nib4;
|
||||||
|
|
||||||
|
//load bits into static keystream
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
state->static_ks_bits[0][i] = (kperm >> (15-i)) & 1;
|
||||||
|
state->static_ks_bits[1][i] = (kperm >> (15-i)) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr,"DMR Anytone Basic 16-bit Key 0x%04X with Forced Application\n", key);
|
||||||
|
state->any_bp = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void straight_mod_xor_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
uint16_t len = 0;
|
||||||
|
char * curr;
|
||||||
|
curr = strtok(input, ":"); //should be len (mod) of key (decimal)
|
||||||
|
if (curr != NULL)
|
||||||
|
sscanf (curr, "%hd", &len);
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
//len sanity check, can't be greater than 882
|
||||||
|
if (len > 882)
|
||||||
|
len = 882;
|
||||||
|
|
||||||
|
curr = strtok(NULL, ":"); //should be key in hex
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
//continue
|
||||||
|
}
|
||||||
|
else goto END_KS;
|
||||||
|
|
||||||
|
uint8_t ks_bytes[112];
|
||||||
|
memset (ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
parse_raw_user_string(curr, ks_bytes);
|
||||||
|
|
||||||
|
uint8_t ks_bits[896];
|
||||||
|
memset(ks_bits, 0, sizeof(ks_bits));
|
||||||
|
|
||||||
|
uint16_t unpack_len = len / 8;
|
||||||
|
if (len % 8)
|
||||||
|
unpack_len++;
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks_bits, unpack_len);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
state->static_ks_bits[0][i] = ks_bits[i];
|
||||||
|
state->static_ks_bits[1][i] = ks_bits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr,"AMBE Straight XOR %d-bit Keystream: ", len);
|
||||||
|
for (uint16_t i = 0; i < unpack_len; i++)
|
||||||
|
fprintf (stderr, "%02X", ks_bytes[i]);
|
||||||
|
fprintf (stderr, " with Forced Application \n");
|
||||||
|
|
||||||
|
state->straight_ks = 1;
|
||||||
|
state->straight_mod = (int)len;
|
||||||
|
|
||||||
|
END_KS:
|
||||||
|
|
||||||
|
if (curr == NULL)
|
||||||
|
fprintf (stderr, "Straight KS String Malformed! No KS Created!\n");
|
||||||
|
|
||||||
|
}
|
||||||
417
src/crypt-kir.c
Normal file
417
src/crypt-kir.c
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
#include "dsd.h"
|
||||||
|
#include "pc4.h"
|
||||||
|
|
||||||
|
/* === Global MD2II buffers === */
|
||||||
|
int x1, x2, i, n1global;
|
||||||
|
unsigned char h2[n1];
|
||||||
|
unsigned char h1[n1*3];
|
||||||
|
|
||||||
|
/* === MD2II functions === */
|
||||||
|
void MD2II_init()
|
||||||
|
{
|
||||||
|
x1 = 0;
|
||||||
|
x2 = 0;
|
||||||
|
for (i = 0; i < n1global; i++)
|
||||||
|
h2[i] = 0;
|
||||||
|
for (i = 0; i < n1global; i++)
|
||||||
|
h1[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MD2II_hashing(unsigned char t1[], size_t b6)
|
||||||
|
{
|
||||||
|
static unsigned char s4[256] =
|
||||||
|
{13,199,11,67,237,193,164,77,115,184,141,222,73,
|
||||||
|
38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||||
|
119,22,207,35,198,37,171,167,80,30,219,28,213,
|
||||||
|
121,86,29,214,242,6,4,89,162,110,175,19,157,
|
||||||
|
3,88,234,94,144,118,159,239,100,17,182,173,238,
|
||||||
|
68,16,79,132,54,163,52,9,58,57,55,229,192,
|
||||||
|
170,226,56,231,187,158,70,224,233,245,26,47,32,
|
||||||
|
44,247,8,251,20,197,185,109,153,204,218,93,178,
|
||||||
|
212,137,84,174,24,120,130,149,72,180,181,208,255,
|
||||||
|
189,152,18,143,176,60,249,27,227,128,139,243,253,
|
||||||
|
59,123,172,108,211,96,138,10,215,42,225,40,81,
|
||||||
|
65,90,25,98,126,154,64,124,116,122,5,1,168,
|
||||||
|
83,190,131,191,244,240,235,177,155,228,125,66,43,
|
||||||
|
201,248,220,129,188,230,62,75,71,78,34,31,216,
|
||||||
|
254,136,91,114,106,46,217,196,92,151,209,133,51,
|
||||||
|
236,33,252,127,179,69,7,183,105,146,97,39,15,
|
||||||
|
205,112,200,166,223,45,48,246,186,41,148,140,107,
|
||||||
|
76,85,95,194,142,50,49,134,23,135,169,221,210,
|
||||||
|
203,63,165,82,161,202,53,14,206,232,103,102,195,
|
||||||
|
117,250,99,0,74,160,241,2,113};
|
||||||
|
|
||||||
|
int b1, b2, b3, b4 = 0, b5;
|
||||||
|
|
||||||
|
while (b6) {
|
||||||
|
for (; b6 && x2 < n1global; b6--, x2++) {
|
||||||
|
b5 = t1[b4++];
|
||||||
|
h1[x2 + n1global] = b5;
|
||||||
|
h1[x2 + (n1global*2)] = b5 ^ h1[x2];
|
||||||
|
x1 = h2[x2] ^= s4[b5 ^ x1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x2 == n1global) {
|
||||||
|
b2 = 0;
|
||||||
|
x2 = 0;
|
||||||
|
for (b3 = 0; b3 < (n1global+2); b3++) {
|
||||||
|
for (b1 = 0; b1 < (n1global*3); b1++)
|
||||||
|
b2 = h1[b1] ^= s4[b2];
|
||||||
|
b2 = (b2 + b3) % 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MD2II_end(unsigned char h4[n1])
|
||||||
|
{
|
||||||
|
unsigned char h3[n1];
|
||||||
|
int i, n4;
|
||||||
|
n4 = n1global - x2;
|
||||||
|
for (i = 0; i < n4; i++) h3[i] = n4;
|
||||||
|
MD2II_hashing(h3, n4);
|
||||||
|
MD2II_hashing(h2, n1global);
|
||||||
|
for (i = 0; i < n1global; i++) h4[i] = h1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hex(const unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
printf("%02X ", buf[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t rol48(uint64_t x, int n)
|
||||||
|
{
|
||||||
|
return ((x << n) | (x >> 47)) & 0xffffffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Keystream (A5-like) === */
|
||||||
|
static int threshold(uint64_t r1, uint64_t r2, uint64_t r3)
|
||||||
|
{
|
||||||
|
int total = (((r1 >> 31) & 1) == 1) +
|
||||||
|
(((r2 >> 31) & 1) == 1) +
|
||||||
|
(((r3 >> 31) & 1) == 1);
|
||||||
|
return (total > 1) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t clock_r1(int ctl, uint64_t r1)
|
||||||
|
{
|
||||||
|
ctl ^= ((r1 >> 31) & 1);
|
||||||
|
if (ctl) {
|
||||||
|
int taps[] = {0,3,5,9,10,11,12,17,18,28,33,34,35,36,37,39,42,43,44,46,47,49,50,57,60,61,62,63};
|
||||||
|
uint64_t fb = 0;
|
||||||
|
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r1>>taps[i])&1ULL;
|
||||||
|
r1 = (r1<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||||
|
if(fb&1ULL) r1 ^= 1ULL;
|
||||||
|
}
|
||||||
|
return r1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t clock_r2(int ctl, uint64_t r2)
|
||||||
|
{
|
||||||
|
ctl ^= ((r2 >> 31) & 1);
|
||||||
|
if (ctl) {
|
||||||
|
int taps[] = {0,3,5,8,9,10,12,13,15,17,19,20,21,22,24,27,30,31,33,34,35,36,37,40,41,42,51,52,55,56,59,60,62,63};
|
||||||
|
uint64_t fb = 0;
|
||||||
|
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r2>>taps[i])&1ULL;
|
||||||
|
r2 = (r2<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||||
|
if(fb&1ULL) r2 ^= 1ULL;
|
||||||
|
}
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t clock_r3(int ctl, uint64_t r3)
|
||||||
|
{
|
||||||
|
ctl ^= ((r3 >> 31) & 1);
|
||||||
|
if (ctl) {
|
||||||
|
int taps[] = {1,2,4,5,6,7,8,9,10,14,15,16,17,18,22,23,25,26,27,28,29,31,32,34,35,36,38,41,42,43,44,45,47,48,49,50,51,54,55,59,61,63};
|
||||||
|
uint64_t fb = 0;
|
||||||
|
for(int i=0;i<sizeof(taps)/sizeof(int);i++) fb ^= (r3>>taps[i])&1ULL;
|
||||||
|
r3 = (r3<<1)&0xFFFFFFFFFFFFFFFFULL;
|
||||||
|
if(fb&1ULL) r3 ^= 1ULL;
|
||||||
|
}
|
||||||
|
return r3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void keystream37(unsigned char *key, uint64_t frame, unsigned char *output)
|
||||||
|
{
|
||||||
|
uint64_t r1=0,r2=0,r3=0;
|
||||||
|
for(int i=0;i<8;i++) r1=(r1<<8)|key[i];
|
||||||
|
for(int i=0;i<8;i++) r2=(r2<<8)|key[i+8];
|
||||||
|
for(int i=0;i<8;i++) r3=(r3<<8)|key[i+16];
|
||||||
|
|
||||||
|
for(int i=0;i<64;i++){
|
||||||
|
int ctl=threshold(r1,r2,r3);
|
||||||
|
r1=clock_r1(ctl,r1);
|
||||||
|
r2=clock_r2(ctl,r2);
|
||||||
|
r3=clock_r3(ctl,r3);
|
||||||
|
if(frame&1ULL){ r1^=1ULL; r2^=1ULL; r3^=1ULL;}
|
||||||
|
frame>>=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<384;i++){
|
||||||
|
int ctl=threshold(r1,r2,r3);
|
||||||
|
r1=clock_r1(ctl,r1);
|
||||||
|
r2=clock_r2(ctl,r2);
|
||||||
|
r3=clock_r3(ctl,r3);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *ptr=output;
|
||||||
|
unsigned char byte=0;
|
||||||
|
int bits=0;
|
||||||
|
for(int i=0;i<1008;i++){
|
||||||
|
int ctl=threshold(r1,r2,r3);
|
||||||
|
r1=clock_r1(ctl,r1);
|
||||||
|
r2=clock_r2(ctl,r2);
|
||||||
|
r3=clock_r3(ctl,r3);
|
||||||
|
int bit=((r1>>63)^(r2>>63)^(r3>>63))&1U;
|
||||||
|
byte=(byte<<1)|bit;
|
||||||
|
bits++;
|
||||||
|
if(bits==8){*ptr++=byte; bits=0; byte=0;}
|
||||||
|
}
|
||||||
|
if(bits) *ptr=byte;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//dsd-fme -fs -Z -i '/SSD_STORAGE/2025_DEV/Tytera BP EP AP Master Folder/kirisun/cap-clear.wav/cap-33.wav' -H '3333333333333333 3333333333333333 3333333333333333 3333333333333333'
|
||||||
|
void kirisun_uni_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
uint8_t slot = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
slot = 0;
|
||||||
|
else slot = 1;
|
||||||
|
|
||||||
|
uint32_t lfsr = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
lfsr = (uint32_t)state->payload_mi;
|
||||||
|
else lfsr = (uint32_t)state->payload_miR;
|
||||||
|
|
||||||
|
unsigned char userkeyhexa[32]; memset(userkeyhexa, 0, sizeof(userkeyhexa));
|
||||||
|
unsigned char realkey[32]; memset(realkey, 0, sizeof(realkey));
|
||||||
|
unsigned char lfsrhexa[4]; memset(lfsrhexa, 0, sizeof(lfsrhexa));
|
||||||
|
uint8_t ks_bytes[126]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
lfsrhexa[0] = (lfsr >> 24) & 0xFF;
|
||||||
|
lfsrhexa[1] = (lfsr >> 16) & 0xFF;
|
||||||
|
lfsrhexa[2] = (lfsr >> 8) & 0xFF;
|
||||||
|
lfsrhexa[3] = (lfsr >> 0) & 0xFF;
|
||||||
|
|
||||||
|
uint64_t K1 = state->A1[slot];
|
||||||
|
uint64_t K2 = state->A2[slot];
|
||||||
|
uint64_t K3 = state->A3[slot];
|
||||||
|
uint64_t K4 = state->A4[slot];
|
||||||
|
|
||||||
|
if (K1 != 0 && K2 != 0 && K3 != 0 && K4 != 0)
|
||||||
|
state->aes_key_loaded[slot] = 1;
|
||||||
|
else state->aes_key_loaded[slot] = 0;
|
||||||
|
|
||||||
|
if (state->aes_key_loaded[slot] == 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
u64_to_bytes_be(K1, &userkeyhexa[0]);
|
||||||
|
u64_to_bytes_be(K2, &userkeyhexa[8]);
|
||||||
|
u64_to_bytes_be(K3, &userkeyhexa[16]);
|
||||||
|
u64_to_bytes_be(K4, &userkeyhexa[24]);
|
||||||
|
|
||||||
|
for(int i=0;i<32;i++) realkey[i]=userkeyhexa[i];
|
||||||
|
|
||||||
|
/* --- MD2II first pass --- */
|
||||||
|
n1global=32;
|
||||||
|
unsigned char h4[n1]; memset(h4, 0, sizeof(h4));
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
for(int i=0;i<32;i++) realkey[i]=h4[i];
|
||||||
|
|
||||||
|
// printf("=== realkey final (32 bytes) ===\n");
|
||||||
|
// print_hex(realkey,32);
|
||||||
|
|
||||||
|
/* --- MD2II with n1global=8, hash lfsr byte by byte --- */
|
||||||
|
unsigned char hashtag[1];
|
||||||
|
|
||||||
|
n1global=8;
|
||||||
|
MD2II_init();
|
||||||
|
for(int i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
hashtag[0] = (lfsr >> (24-8*i)) & 0xFF;
|
||||||
|
MD2II_hashing(hashtag,1);
|
||||||
|
}
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("h4[0..7]: ");
|
||||||
|
// print_hex(h4,8);
|
||||||
|
|
||||||
|
uint64_t internal_state=0;
|
||||||
|
for(int i=0;i<8;i++)
|
||||||
|
internal_state=(internal_state<<8)+(h4[i]);
|
||||||
|
|
||||||
|
// printf("internal_state=%016llX\n",(unsigned long long)internal_state);
|
||||||
|
|
||||||
|
/* --- MD2II with n1global=24 --- */
|
||||||
|
n1global=24;
|
||||||
|
MD2II_init();
|
||||||
|
for(int i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
hashtag[0] = (lfsr >> (24-8*i)) & 0xFF;
|
||||||
|
MD2II_hashing(hashtag,1);
|
||||||
|
}
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("realkey (24 bytes):\n");
|
||||||
|
// print_hex(h4,24);
|
||||||
|
|
||||||
|
/* --- keystream output --- */
|
||||||
|
unsigned char output[126]; memset(output, 0, sizeof(output));
|
||||||
|
keystream37(h4, internal_state, output);
|
||||||
|
|
||||||
|
// printf("keystream output (126 bytes):\n");
|
||||||
|
// print_hex(output,126);
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
for (int i = 0; i < 126; i++)
|
||||||
|
ks_bytes[i] = (uint8_t)output[i];
|
||||||
|
|
||||||
|
if (slot == 0)
|
||||||
|
memcpy(state->ks_octetL, ks_bytes, sizeof(ks_bytes));
|
||||||
|
else memcpy(state->ks_octetR, ks_bytes, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
//debug ks_bytes
|
||||||
|
// fprintf (stderr, "KS: ");
|
||||||
|
// for (int i = 0; i < 126; i++)
|
||||||
|
// {
|
||||||
|
// if ((i != 0) && ((i%16)==0))
|
||||||
|
// fprintf (stderr, "\n ");
|
||||||
|
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||||
|
// }
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//dsd-fme -fs -Z -i '/SSD_STORAGE/2025_DEV/Tytera BP EP AP Master Folder/kirisun/better_samples_tg1/kirisun_advanced_tg1.wav' -H 'DC1A7E9F9BF312DB F45010CEC5F7A53A C407D0BFA803617B E426A7254DA9390D'
|
||||||
|
void kirisun_adv_keystream_creation(dsd_state *state)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t slot = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
slot = 0;
|
||||||
|
else slot = 1;
|
||||||
|
|
||||||
|
uint32_t lfsr = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
lfsr = (uint32_t)state->payload_mi;
|
||||||
|
else lfsr = (uint32_t)state->payload_miR;
|
||||||
|
|
||||||
|
unsigned char userkeyhexa[32]; memset(userkeyhexa, 0, sizeof(userkeyhexa));
|
||||||
|
unsigned char realkey[32]; memset(realkey, 0, sizeof(realkey));
|
||||||
|
unsigned char lfsrhexa[4]; memset(lfsrhexa, 0, sizeof(lfsrhexa));
|
||||||
|
uint8_t ks_bytes[126]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
lfsrhexa[0] = (lfsr >> 24) & 0xFF;
|
||||||
|
lfsrhexa[1] = (lfsr >> 16) & 0xFF;
|
||||||
|
lfsrhexa[2] = (lfsr >> 8) & 0xFF;
|
||||||
|
lfsrhexa[3] = (lfsr >> 0) & 0xFF;
|
||||||
|
|
||||||
|
uint64_t K1 = state->A1[slot];
|
||||||
|
uint64_t K2 = state->A2[slot];
|
||||||
|
uint64_t K3 = state->A3[slot];
|
||||||
|
uint64_t K4 = state->A4[slot];
|
||||||
|
|
||||||
|
if (K1 != 0 && K2 != 0 && K3 != 0 && K4 != 0)
|
||||||
|
state->aes_key_loaded[slot] = 1;
|
||||||
|
else state->aes_key_loaded[slot] = 0;
|
||||||
|
|
||||||
|
if (state->aes_key_loaded[slot] == 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
u64_to_bytes_be(K1, &userkeyhexa[0]);
|
||||||
|
u64_to_bytes_be(K2, &userkeyhexa[8]);
|
||||||
|
u64_to_bytes_be(K3, &userkeyhexa[16]);
|
||||||
|
u64_to_bytes_be(K4, &userkeyhexa[24]);
|
||||||
|
|
||||||
|
//init vital portions of PC4Context
|
||||||
|
ctx.x1 = 0;
|
||||||
|
ctx.x2 = 0;
|
||||||
|
for (ctx.i = 0; ctx.i < n1; ctx.i++) ctx.h2[ctx.i] = 0;
|
||||||
|
for (ctx.i = 0; ctx.i < n1; ctx.i++) ctx.h1[ctx.i] = 0;
|
||||||
|
ctx.rounds = nbround;
|
||||||
|
|
||||||
|
//create keys
|
||||||
|
create_keys(&ctx, userkeyhexa, 32);
|
||||||
|
|
||||||
|
/* --- MD2II first pass --- */
|
||||||
|
n1global=32;
|
||||||
|
unsigned char h4[n1]; memset(h4, 0, sizeof(h4));
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(userkeyhexa,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
for(int i=0;i<32;i++) realkey[i]=h4[i];
|
||||||
|
|
||||||
|
// printf("=== realkey final (32 bytes) ===\n");
|
||||||
|
// print_hex(realkey,32);
|
||||||
|
|
||||||
|
n1global=32;
|
||||||
|
memset(h4, 0, sizeof(h4));
|
||||||
|
MD2II_init();
|
||||||
|
MD2II_hashing(lfsrhexa,4);
|
||||||
|
MD2II_hashing(realkey,32);
|
||||||
|
MD2II_end(h4);
|
||||||
|
|
||||||
|
// printf("h4[0..7]: ");
|
||||||
|
// print_hex(h4,8);
|
||||||
|
|
||||||
|
uint64_t internal_state=0;
|
||||||
|
for(int i=0;i<6;i++)
|
||||||
|
internal_state=(internal_state<<8)+(h4[i]);
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (int i = 0; i < 18; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//debug internal_state
|
||||||
|
// fprintf (stderr, "ST: %012lX; \n", internal_state);
|
||||||
|
|
||||||
|
ctx.convert[0]=(internal_state>>40)&0xff;
|
||||||
|
ctx.convert[1]=(internal_state>>32)&0xff;
|
||||||
|
ctx.convert[2]=(internal_state>>24)&0xff;
|
||||||
|
ctx.convert[3]=(internal_state>>16)&0xff;
|
||||||
|
ctx.convert[4]=(internal_state>>8)&0xff;
|
||||||
|
ctx.convert[5]=internal_state&0xff;
|
||||||
|
|
||||||
|
pc4encrypt(&ctx);
|
||||||
|
|
||||||
|
internal_state=0;
|
||||||
|
for (int i=0;i<6;i++)
|
||||||
|
internal_state=(internal_state<<8)+(ctx.convert[i]&0xff);
|
||||||
|
|
||||||
|
internal_state=rol48(internal_state,1);
|
||||||
|
|
||||||
|
//keystream
|
||||||
|
for (int i=0;i<6;i++)
|
||||||
|
ks_bytes[k++] = ctx.convert[i];
|
||||||
|
k++; //skip 7th octet
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//store ks_bytes to storage
|
||||||
|
if (slot == 0)
|
||||||
|
memcpy(state->ks_octetL, ks_bytes, sizeof(ks_bytes));
|
||||||
|
else memcpy(state->ks_octetR, ks_bytes, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
//debug ks_bytes
|
||||||
|
// fprintf (stderr, "KS: ");
|
||||||
|
// for (int i = 0; i < 126; i++)
|
||||||
|
// {
|
||||||
|
// if ((i != 0) && ((i%16)==0))
|
||||||
|
// fprintf (stderr, "\n ");
|
||||||
|
// fprintf (stderr, "%02X ", ks_bytes[i]);
|
||||||
|
// }
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
392
src/crypt-pc4.c
Normal file
392
src/crypt-pc4.c
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
#include "pc4.h"
|
||||||
|
|
||||||
|
/* Global PC4 context instance */
|
||||||
|
PC4Context ctx;
|
||||||
|
|
||||||
|
/* ---------------------------------
|
||||||
|
Internal utility functions
|
||||||
|
----------------------------------- */
|
||||||
|
|
||||||
|
/* Rotate right */
|
||||||
|
static uint32_t ror(uint32_t x, int shift, int bits) {
|
||||||
|
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||||
|
uint32_t m1 = (1u << shift) - 1u;
|
||||||
|
return ((x >> shift) & m0) | ((x & m1) << (bits - shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rotate left */
|
||||||
|
static uint32_t rol(uint32_t x, int shift, int bits) {
|
||||||
|
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||||
|
uint32_t m1 = (1u << shift) - 1u;
|
||||||
|
return ((x & m0) << shift) | ((x >> (bits - shift)) & m1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SplitMix64 random number generator */
|
||||||
|
static uint64_t next_rng(PC4Context *ctx) {
|
||||||
|
uint64_t z = (ctx->x += 0x9e3779b97f4a7c15ULL);
|
||||||
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
||||||
|
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
||||||
|
return z ^ (z >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARC4 initialization */
|
||||||
|
static void arc4_init(PC4Context *ctx, unsigned char key[]) {
|
||||||
|
int tmp;
|
||||||
|
for (ctx->i_arc4 = 0; ctx->i_arc4 < 256; ctx->i_arc4++)
|
||||||
|
ctx->array_arc4[ctx->i_arc4] = (unsigned char)ctx->i_arc4;
|
||||||
|
|
||||||
|
ctx->j_arc4 = 0;
|
||||||
|
for (ctx->i_arc4 = 0; ctx->i_arc4 < 256; ctx->i_arc4++) {
|
||||||
|
ctx->j_arc4 = (ctx->j_arc4 + ctx->array_arc4[ctx->i_arc4] + key[ctx->i_arc4 % 256]) % 256;
|
||||||
|
tmp = ctx->array_arc4[ctx->i_arc4];
|
||||||
|
ctx->array_arc4[ctx->i_arc4] = ctx->array_arc4[ctx->j_arc4];
|
||||||
|
ctx->array_arc4[ctx->j_arc4] = tmp;
|
||||||
|
}
|
||||||
|
ctx->i_arc4 = 0;
|
||||||
|
ctx->j_arc4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARC4 output combined with SplitMix64 stream */
|
||||||
|
static unsigned char arc4_output(PC4Context *ctx) {
|
||||||
|
uint8_t rndbyte, decal;
|
||||||
|
int tmp, t;
|
||||||
|
|
||||||
|
ctx->i_arc4 = (ctx->i_arc4 + 1) % 256;
|
||||||
|
ctx->j_arc4 = (ctx->j_arc4 + ctx->array_arc4[ctx->i_arc4]) % 256;
|
||||||
|
tmp = ctx->array_arc4[ctx->i_arc4];
|
||||||
|
ctx->array_arc4[ctx->i_arc4] = ctx->array_arc4[ctx->j_arc4];
|
||||||
|
ctx->array_arc4[ctx->j_arc4] = tmp;
|
||||||
|
t = (ctx->array_arc4[ctx->i_arc4] + ctx->array_arc4[ctx->j_arc4]) % 256;
|
||||||
|
|
||||||
|
if (ctx->xyz == 0) ctx->bb = next_rng(ctx);
|
||||||
|
decal = (uint8_t)(56 - (8 * ctx->xyz));
|
||||||
|
rndbyte = (uint8_t)((ctx->bb >> decal) & 0xffu);
|
||||||
|
ctx->xyz++;
|
||||||
|
if (ctx->xyz == 8) ctx->xyz = 0;
|
||||||
|
|
||||||
|
if (ctx->count == 0) {
|
||||||
|
rndbyte = (uint8_t)(rndbyte ^ ctx->array_arc4[t]);
|
||||||
|
ctx->count = 1;
|
||||||
|
} else {
|
||||||
|
rndbyte = (uint8_t)(rndbyte + ctx->array_arc4[t]);
|
||||||
|
ctx->count = 0;
|
||||||
|
}
|
||||||
|
return rndbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize MD2-II state */
|
||||||
|
static void md2_init(PC4Context *ctx) {
|
||||||
|
ctx->x1 = 0;
|
||||||
|
ctx->x2 = 0;
|
||||||
|
for (ctx->i = 0; ctx->i < n1; ctx->i++) ctx->h2[ctx->i] = 0;
|
||||||
|
for (ctx->i = 0; ctx->i < n1; ctx->i++) ctx->h1[ctx->i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD2-II hashing */
|
||||||
|
static void md2_hashing(PC4Context *ctx, unsigned char t1[], size_t b6) {
|
||||||
|
static const unsigned char s4[256] = {
|
||||||
|
13,199,11,67,237,193,164,77,115,184,141,222,73,38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||||
|
119,22,207,35,198,37,171,167,80,30,219,28,213,121,86,29,214,242,6,4,89,162,110,175,19,157,3,
|
||||||
|
88,234,94,144,118,159,239,100,17,182,173,238,68,16,79,132,54,163,52,9,58,57,55,229,192,170,226,
|
||||||
|
56,231,187,158,70,224,233,245,26,47,32,44,247,8,251,20,197,185,109,153,204,218,93,178,212,137,84,
|
||||||
|
174,24,120,130,149,72,180,181,208,255,189,152,18,143,176,60,249,27,227,128,139,243,253,59,123,172,
|
||||||
|
108,211,96,138,10,215,42,225,40,81,65,90,25,98,126,154,64,124,116,122,5,1,168,83,190,131,191,244,
|
||||||
|
240,235,177,155,228,125,66,43,201,248,220,129,188,230,62,75,71,78,34,31,216,254,136,91,114,106,46,
|
||||||
|
217,196,92,151,209,133,51,236,33,252,127,179,69,7,183,105,146,97,39,15,205,112,200,166,223,45,48,
|
||||||
|
246,186,41,148,140,107,76,85,95,194,142,50,49,134,23,135,169,221,210,203,63,165,82,161,202,53,14,
|
||||||
|
206,232,103,102,195,117,250,99,0,74,160,241,2,113};
|
||||||
|
|
||||||
|
int b1, b2, b3, b4, b5;
|
||||||
|
b4 = 0;
|
||||||
|
while (b6) {
|
||||||
|
for (; b6 && ctx->x2 < n1; b6--, ctx->x2++) {
|
||||||
|
b5 = t1[b4++];
|
||||||
|
ctx->h1[ctx->x2 + n1] = (unsigned char)b5;
|
||||||
|
ctx->h1[ctx->x2 + (n1 * 2)] = (unsigned char)(b5 ^ ctx->h1[ctx->x2]);
|
||||||
|
ctx->x1 = ctx->h2[ctx->x2] ^= s4[b5 ^ ctx->x1];
|
||||||
|
}
|
||||||
|
if (ctx->x2 == n1) {
|
||||||
|
b2 = 0;
|
||||||
|
ctx->x2 = 0;
|
||||||
|
for (b3 = 0; b3 < (n1 + 2); b3++) {
|
||||||
|
for (b1 = 0; b1 < (n1 * 3); b1++)
|
||||||
|
b2 = ctx->h1[b1] ^= s4[b2];
|
||||||
|
b2 = (b2 + b3) % 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize MD2-II */
|
||||||
|
static void md2_end(PC4Context *ctx, unsigned char h4[n1]) {
|
||||||
|
unsigned char h3[n1];
|
||||||
|
int i, n4 = n1 - ctx->x2;
|
||||||
|
for (i = 0; i < n4; i++) h3[i] = (unsigned char)n4;
|
||||||
|
md2_hashing(ctx, h3, (size_t)n4);
|
||||||
|
md2_hashing(ctx, ctx->h2, sizeof(ctx->h2));
|
||||||
|
for (i = 0; i < n1; i++) h4[i] = ctx->h1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a random index */
|
||||||
|
static int mixy(PC4Context *ctx, int nn2) {
|
||||||
|
return arc4_output(ctx) % nn2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fisher-Yates shuffle */
|
||||||
|
static void mixer(PC4Context *ctx, uint8_t *mixu, int nn) {
|
||||||
|
int ii, jj, tmmp;
|
||||||
|
for (ii = nn - 1; ii > 0; ii--) {
|
||||||
|
jj = mixy(ctx, ii + 1);
|
||||||
|
tmmp = mixu[jj];
|
||||||
|
mixu[jj] = mixu[ii];
|
||||||
|
mixu[ii] = (uint8_t)tmmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key schedule and S-box generation */
|
||||||
|
void create_keys(PC4Context *ctx, unsigned char key1[], size_t size1) {
|
||||||
|
int i, w, k;
|
||||||
|
unsigned char h4[n1];
|
||||||
|
|
||||||
|
md2_init(ctx);
|
||||||
|
md2_hashing(ctx, key1, size1);
|
||||||
|
md2_end(ctx, h4);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) ctx->keys[i] = h4[i];
|
||||||
|
arc4_init(ctx, h4);
|
||||||
|
|
||||||
|
ctx->x = 0;
|
||||||
|
for (i = 0; i < 8; i++) ctx->x = (ctx->x << 8) + (uint64_t)(h4[256 + i] & 0xffu);
|
||||||
|
|
||||||
|
ctx->xyz = 0;
|
||||||
|
ctx->count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 20000; i++) (void)arc4_output(ctx);
|
||||||
|
|
||||||
|
uint8_t numbers[256];
|
||||||
|
|
||||||
|
for (w = 0; w < 16; w++) {
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 256; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 256);
|
||||||
|
for (i = 0; i < 256; i++) ctx->perm[w][i] = numbers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 256; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 256);
|
||||||
|
for (i = 0; i < 256; i++) ctx->new1[i] = numbers[i];
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 49; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 49);
|
||||||
|
for (i = 0; i < 49; i++) ctx->array[i] = numbers[i];
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < nbround; i++) ctx->decal[i] = (uint8_t)((arc4_output(ctx) % 23) + 1);
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (w = 0; w < 3; w++)
|
||||||
|
for (i = 0; i < nbround; i++)
|
||||||
|
ctx->rngxor[i][w] = arc4_output(ctx);
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 49; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 49);
|
||||||
|
for (i = 0; i < 49; i++) ctx->array2[i] = numbers[i];
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 256; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 256);
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
ctx->tab[i] = numbers[i];
|
||||||
|
ctx->inv[ctx->tab[i]] = (unsigned char)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (w = 0; w < 3; w++) {
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (i = 0; i < 3; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctx, numbers, 3);
|
||||||
|
for (i = 0; i < 3; i++) ctx->permut[w][i] = numbers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
k = arc4_output(ctx) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctx);
|
||||||
|
for (w = 0; w < 3; w++)
|
||||||
|
for (i = 0; i < nbround; i++)
|
||||||
|
ctx->rngxor2[i][w] = arc4_output(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute round transformation */
|
||||||
|
static void compute(PC4Context *ctx, uint8_t *tab1, uint8_t round) {
|
||||||
|
ctx->tot[0] = (uint8_t)((ctx->perm[round][tab1[ctx->permut[0][0]]] +
|
||||||
|
ctx->perm[round][tab1[ctx->permut[0][1]]]) ^
|
||||||
|
ctx->perm[round][tab1[ctx->permut[0][2]]]);
|
||||||
|
ctx->tot[0] = (uint8_t)(ctx->tot[0] + ctx->new1[ctx->tot[0]]);
|
||||||
|
ctx->tot[1] = (uint8_t)((ctx->perm[round][tab1[ctx->permut[1][0]]] +
|
||||||
|
ctx->perm[round][tab1[ctx->permut[1][1]]]) ^
|
||||||
|
ctx->perm[round][tab1[ctx->permut[1][2]]]);
|
||||||
|
ctx->tot[1] = (uint8_t)(ctx->tot[1] + ctx->new1[ctx->tot[1]]);
|
||||||
|
ctx->tot[2] = (uint8_t)((ctx->perm[round][tab1[ctx->permut[2][0]]] +
|
||||||
|
ctx->perm[round][tab1[ctx->permut[2][1]]]) ^
|
||||||
|
ctx->perm[round][tab1[ctx->permut[2][2]]]);
|
||||||
|
ctx->tot[2] = (uint8_t)(ctx->tot[2] + ctx->new1[ctx->tot[2]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert bits to bytes */
|
||||||
|
void binhex(PC4Context *ctx, short *z, int length) {
|
||||||
|
short *b = (short *)z;
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < length; i = j) {
|
||||||
|
uint8_t a = 0;
|
||||||
|
for (j = i; j < i + 8; ++j) {
|
||||||
|
a |= (uint8_t)(b[((short)(7 - (j % 8)) + j) - (j % 8)] << (j - i));
|
||||||
|
}
|
||||||
|
ctx->convert[ctx->ptconvert] = a;
|
||||||
|
ctx->ptconvert++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert byte to bits */
|
||||||
|
void hexbin(PC4Context *ctx, short *q, uint8_t w, uint8_t hex) { // warning: unused parameter ‘ctx’ [-Wunused-parameter]
|
||||||
|
short *bits = (short *)q;
|
||||||
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
|
bits[(short)(7 + w) - i] = (short)((hex >> i) & 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNUSEDPC4(ctx); //fix above warning
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encrypt one block */
|
||||||
|
void pc4encrypt(PC4Context *ctx) {
|
||||||
|
int i;
|
||||||
|
ctx->totb = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctx->l[0][i] = ctx->convert[i];
|
||||||
|
ctx->r[0][i] = ctx->convert[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i <= ctx->rounds; i++) {
|
||||||
|
ctx->totb ^= ctx->r[(i - 1) % 2][0];
|
||||||
|
ctx->totb ^= ctx->r[(i - 1) % 2][1];
|
||||||
|
ctx->totb ^= ctx->r[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctx->r[(i - 1) % 2][0] += (uint8_t)(~ctx->rngxor2[ctx->rounds - i][0]);
|
||||||
|
ctx->r[(i - 1) % 2][1] ^= (uint8_t)(~ctx->rngxor2[ctx->rounds - i][1]);
|
||||||
|
ctx->r[(i - 1) % 2][2] += (uint8_t)(~ctx->rngxor2[ctx->rounds - i][2]);
|
||||||
|
|
||||||
|
ctx->result = 0;
|
||||||
|
ctx->result += ((uint32_t)ctx->r[(i - 1) % 2][0] << 16);
|
||||||
|
ctx->result += ((uint32_t)ctx->r[(i - 1) % 2][1] << 8);
|
||||||
|
ctx->result += ctx->r[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctx->result = rol(ctx->result, ctx->decal[i - 1], 24);
|
||||||
|
|
||||||
|
ctx->r[(i - 1) % 2][0] = (uint8_t)(ctx->result >> 16);
|
||||||
|
ctx->r[(i - 1) % 2][1] = (uint8_t)((ctx->result >> 8) & 0xffu);
|
||||||
|
ctx->r[(i - 1) % 2][2] = (uint8_t)(ctx->result & 0xffu);
|
||||||
|
|
||||||
|
ctx->r[(i - 1) % 2][0] = ctx->tab[ctx->r[(i - 1) % 2][0]];
|
||||||
|
ctx->r[(i - 1) % 2][0] ^= ctx->rngxor[i - 1][0];
|
||||||
|
|
||||||
|
ctx->r[(i - 1) % 2][1] = ctx->inv[ctx->r[(i - 1) % 2][1]];
|
||||||
|
ctx->r[(i - 1) % 2][1] -= ctx->rngxor[i - 1][1];
|
||||||
|
|
||||||
|
ctx->r[(i - 1) % 2][2] = ctx->tab[ctx->r[(i - 1) % 2][2]];
|
||||||
|
ctx->r[(i - 1) % 2][2] ^= ctx->rngxor[i - 1][2];
|
||||||
|
|
||||||
|
compute(ctx, ctx->r[(i - 1) % 2], (uint8_t)((i - 1) % 16));
|
||||||
|
|
||||||
|
ctx->l[i % 2][0] = ctx->r[(i - 1) % 2][0];
|
||||||
|
ctx->r[i % 2][0] = ctx->l[(i - 1) % 2][0] - ctx->tot[0];
|
||||||
|
|
||||||
|
ctx->l[i % 2][1] = ctx->r[(i - 1) % 2][1];
|
||||||
|
ctx->r[i % 2][1] = ctx->l[(i - 1) % 2][1] ^ ctx->tot[1];
|
||||||
|
|
||||||
|
ctx->l[i % 2][2] = ctx->r[(i - 1) % 2][2];
|
||||||
|
ctx->r[i % 2][2] = ctx->l[(i - 1) % 2][2] - ctx->tot[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctx->convert[i + 3] = ctx->l[(ctx->rounds - 1) % 2][i];
|
||||||
|
ctx->convert[i] = ctx->r[(ctx->rounds - 1) % 2][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->totb %= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt one block */
|
||||||
|
void pc4decrypt(PC4Context *ctx) {
|
||||||
|
int i;
|
||||||
|
ctx->totb = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctx->l[0][i] = ctx->convert[i];
|
||||||
|
ctx->r[0][i] = ctx->convert[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->y = (uint8_t)((ctx->rounds - 1) % 16);
|
||||||
|
if (ctx->y == 0) ctx->y = 16;
|
||||||
|
|
||||||
|
for (i = 1; i <= ctx->rounds; i++) {
|
||||||
|
ctx->y--;
|
||||||
|
compute(ctx, ctx->r[(i - 1) % 2], ctx->y);
|
||||||
|
if (ctx->y == 0) ctx->y = 16;
|
||||||
|
|
||||||
|
ctx->result = 0;
|
||||||
|
|
||||||
|
ctx->l[(i - 1) % 2][0] ^= ctx->rngxor[ctx->rounds - i][0];
|
||||||
|
ctx->l[(i - 1) % 2][0] = ctx->inv[ctx->l[(i - 1) % 2][0]];
|
||||||
|
|
||||||
|
ctx->l[(i - 1) % 2][1] += ctx->rngxor[ctx->rounds - i][1];
|
||||||
|
ctx->l[(i - 1) % 2][1] = ctx->tab[ctx->l[(i - 1) % 2][1]];
|
||||||
|
|
||||||
|
ctx->l[(i - 1) % 2][2] ^= ctx->rngxor[ctx->rounds - i][2];
|
||||||
|
ctx->l[(i - 1) % 2][2] = ctx->inv[ctx->l[(i - 1) % 2][2]];
|
||||||
|
|
||||||
|
ctx->result += ((uint32_t)ctx->l[(i - 1) % 2][0] << 16);
|
||||||
|
ctx->result += ((uint32_t)ctx->l[(i - 1) % 2][1] << 8);
|
||||||
|
ctx->result += ctx->l[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctx->result = ror(ctx->result, ctx->decal[ctx->rounds - i], 24);
|
||||||
|
|
||||||
|
ctx->l[(i - 1) % 2][0] = (uint8_t)(ctx->result >> 16);
|
||||||
|
ctx->l[(i - 1) % 2][1] = (uint8_t)((ctx->result >> 8) & 0xffu);
|
||||||
|
ctx->l[(i - 1) % 2][2] = (uint8_t)(ctx->result & 0xffu);
|
||||||
|
|
||||||
|
ctx->l[(i - 1) % 2][0] -= (uint8_t)(~ctx->rngxor2[i - 1][0]);
|
||||||
|
ctx->l[(i - 1) % 2][1] ^= (uint8_t)(~ctx->rngxor2[i - 1][1]);
|
||||||
|
ctx->l[(i - 1) % 2][2] -= (uint8_t)(~ctx->rngxor2[i - 1][2]);
|
||||||
|
|
||||||
|
ctx->totb ^= ctx->l[(i - 1) % 2][0];
|
||||||
|
ctx->totb ^= ctx->l[(i - 1) % 2][1];
|
||||||
|
ctx->totb ^= ctx->l[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctx->l[i % 2][0] = ctx->r[(i - 1) % 2][0];
|
||||||
|
ctx->r[i % 2][0] = ctx->l[(i - 1) % 2][0] + ctx->tot[0];
|
||||||
|
|
||||||
|
ctx->l[i % 2][1] = ctx->r[(i - 1) % 2][1];
|
||||||
|
ctx->r[i % 2][1] = ctx->l[(i - 1) % 2][1] ^ ctx->tot[1];
|
||||||
|
|
||||||
|
ctx->l[i % 2][2] = ctx->r[(i - 1) % 2][2];
|
||||||
|
ctx->r[i % 2][2] = ctx->l[(i - 1) % 2][2] + ctx->tot[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctx->convert[i + 3] = ctx->l[(ctx->rounds - 1) % 2][i];
|
||||||
|
ctx->convert[i] = ctx->r[(ctx->rounds - 1) % 2][i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->totb %= 2;
|
||||||
|
}
|
||||||
468
src/crypt-pc5.c
Normal file
468
src/crypt-pc5.c
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
#include "pc5.h"
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/* Global PC5 context instance */
|
||||||
|
PC5Context ctxpc5;
|
||||||
|
|
||||||
|
/* ---------------------------------
|
||||||
|
Internal utility functions
|
||||||
|
----------------------------------- */
|
||||||
|
|
||||||
|
/* Rotate right */
|
||||||
|
static uint32_t ror(uint32_t x, int shift, int bits) {
|
||||||
|
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||||
|
uint32_t m1 = (1u << shift) - 1u;
|
||||||
|
return ((x >> shift) & m0) | ((x & m1) << (bits - shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rotate left */
|
||||||
|
static uint32_t rol(uint32_t x, int shift, int bits) {
|
||||||
|
uint32_t m0 = (1u << (bits - shift)) - 1u;
|
||||||
|
uint32_t m1 = (1u << shift) - 1u;
|
||||||
|
return ((x & m0) << shift) | ((x >> (bits - shift)) & m1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SplitMix64 random number generator */
|
||||||
|
static uint64_t next_rng(PC5Context *ctxpc5) {
|
||||||
|
uint64_t z = (ctxpc5->x += 0x9e3779b97f4a7c15ULL);
|
||||||
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
||||||
|
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
||||||
|
return z ^ (z >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARC4 initialization */
|
||||||
|
static void arc4_init(PC5Context *ctxpc5, unsigned char key[]) {
|
||||||
|
int tmp;
|
||||||
|
for (ctxpc5->i_arc4 = 0; ctxpc5->i_arc4 < 256; ctxpc5->i_arc4++)
|
||||||
|
ctxpc5->array_arc4[ctxpc5->i_arc4] = (unsigned char)ctxpc5->i_arc4;
|
||||||
|
|
||||||
|
ctxpc5->j_arc4 = 0;
|
||||||
|
for (ctxpc5->i_arc4 = 0; ctxpc5->i_arc4 < 256; ctxpc5->i_arc4++) {
|
||||||
|
ctxpc5->j_arc4 = (ctxpc5->j_arc4 + ctxpc5->array_arc4[ctxpc5->i_arc4] + key[ctxpc5->i_arc4 % 256]) % 256;
|
||||||
|
tmp = ctxpc5->array_arc4[ctxpc5->i_arc4];
|
||||||
|
ctxpc5->array_arc4[ctxpc5->i_arc4] = ctxpc5->array_arc4[ctxpc5->j_arc4];
|
||||||
|
ctxpc5->array_arc4[ctxpc5->j_arc4] = tmp;
|
||||||
|
}
|
||||||
|
ctxpc5->i_arc4 = 0;
|
||||||
|
ctxpc5->j_arc4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARC4 output combined with SplitMix64 stream */
|
||||||
|
static unsigned char arc4_output(PC5Context *ctxpc5) {
|
||||||
|
uint8_t rndbyte, decal;
|
||||||
|
int tmp, t;
|
||||||
|
|
||||||
|
ctxpc5->i_arc4 = (ctxpc5->i_arc4 + 1) % 256;
|
||||||
|
ctxpc5->j_arc4 = (ctxpc5->j_arc4 + ctxpc5->array_arc4[ctxpc5->i_arc4]) % 256;
|
||||||
|
tmp = ctxpc5->array_arc4[ctxpc5->i_arc4];
|
||||||
|
ctxpc5->array_arc4[ctxpc5->i_arc4] = ctxpc5->array_arc4[ctxpc5->j_arc4];
|
||||||
|
ctxpc5->array_arc4[ctxpc5->j_arc4] = tmp;
|
||||||
|
t = (ctxpc5->array_arc4[ctxpc5->i_arc4] + ctxpc5->array_arc4[ctxpc5->j_arc4]) % 256;
|
||||||
|
|
||||||
|
if (ctxpc5->xyz == 0) ctxpc5->bb = next_rng(ctxpc5);
|
||||||
|
decal = (uint8_t)(56 - (8 * ctxpc5->xyz));
|
||||||
|
rndbyte = (uint8_t)((ctxpc5->bb >> decal) & 0xffu);
|
||||||
|
ctxpc5->xyz++;
|
||||||
|
if (ctxpc5->xyz == 8) ctxpc5->xyz = 0;
|
||||||
|
|
||||||
|
if (ctxpc5->count == 0) {
|
||||||
|
rndbyte = (uint8_t)(rndbyte ^ ctxpc5->array_arc4[t]);
|
||||||
|
ctxpc5->count = 1;
|
||||||
|
} else {
|
||||||
|
rndbyte = (uint8_t)(rndbyte + ctxpc5->array_arc4[t]);
|
||||||
|
ctxpc5->count = 0;
|
||||||
|
}
|
||||||
|
return rndbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize MD2-II state */
|
||||||
|
static void md2_init(PC5Context *ctxpc5) {
|
||||||
|
ctxpc5->x1 = 0;
|
||||||
|
ctxpc5->x2 = 0;
|
||||||
|
for (ctxpc5->i = 0; ctxpc5->i < n1; ctxpc5->i++) ctxpc5->h2[ctxpc5->i] = 0;
|
||||||
|
for (ctxpc5->i = 0; ctxpc5->i < n1; ctxpc5->i++) ctxpc5->h1[ctxpc5->i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD2-II hashing */
|
||||||
|
static void md2_hashing(PC5Context *ctxpc5, unsigned char t1[], size_t b6) {
|
||||||
|
static const unsigned char s4[256] = {
|
||||||
|
13,199,11,67,237,193,164,77,115,184,141,222,73,38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||||
|
119,22,207,35,198,37,171,167,80,30,219,28,213,121,86,29,214,242,6,4,89,162,110,175,19,157,3,
|
||||||
|
88,234,94,144,118,159,239,100,17,182,173,238,68,16,79,132,54,163,52,9,58,57,55,229,192,170,226,
|
||||||
|
56,231,187,158,70,224,233,245,26,47,32,44,247,8,251,20,197,185,109,153,204,218,93,178,212,137,84,
|
||||||
|
174,24,120,130,149,72,180,181,208,255,189,152,18,143,176,60,249,27,227,128,139,243,253,59,123,172,
|
||||||
|
108,211,96,138,10,215,42,225,40,81,65,90,25,98,126,154,64,124,116,122,5,1,168,83,190,131,191,244,
|
||||||
|
240,235,177,155,228,125,66,43,201,248,220,129,188,230,62,75,71,78,34,31,216,254,136,91,114,106,46,
|
||||||
|
217,196,92,151,209,133,51,236,33,252,127,179,69,7,183,105,146,97,39,15,205,112,200,166,223,45,48,
|
||||||
|
246,186,41,148,140,107,76,85,95,194,142,50,49,134,23,135,169,221,210,203,63,165,82,161,202,53,14,
|
||||||
|
206,232,103,102,195,117,250,99,0,74,160,241,2,113};
|
||||||
|
|
||||||
|
int b1, b2, b3, b4, b5;
|
||||||
|
b4 = 0;
|
||||||
|
while (b6) {
|
||||||
|
for (; b6 && ctxpc5->x2 < n1; b6--, ctxpc5->x2++) {
|
||||||
|
b5 = t1[b4++];
|
||||||
|
ctxpc5->h1[ctxpc5->x2 + n1] = (unsigned char)b5;
|
||||||
|
ctxpc5->h1[ctxpc5->x2 + (n1 * 2)] = (unsigned char)(b5 ^ ctxpc5->h1[ctxpc5->x2]);
|
||||||
|
ctxpc5->x1 = ctxpc5->h2[ctxpc5->x2] ^= s4[b5 ^ ctxpc5->x1];
|
||||||
|
}
|
||||||
|
if (ctxpc5->x2 == n1) {
|
||||||
|
b2 = 0;
|
||||||
|
ctxpc5->x2 = 0;
|
||||||
|
for (b3 = 0; b3 < (n1 + 2); b3++) {
|
||||||
|
for (b1 = 0; b1 < (n1 * 3); b1++)
|
||||||
|
b2 = ctxpc5->h1[b1] ^= s4[b2];
|
||||||
|
b2 = (b2 + b3) % 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize MD2-II */
|
||||||
|
static void md2_end(PC5Context *ctxpc5, unsigned char h4[n1]) {
|
||||||
|
unsigned char h3[n1];
|
||||||
|
int i, n4 = n1 - ctxpc5->x2;
|
||||||
|
for (i = 0; i < n4; i++) h3[i] = (unsigned char)n4;
|
||||||
|
md2_hashing(ctxpc5, h3, (size_t)n4);
|
||||||
|
md2_hashing(ctxpc5, ctxpc5->h2, sizeof(ctxpc5->h2));
|
||||||
|
for (i = 0; i < n1; i++) h4[i] = ctxpc5->h1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a random index */
|
||||||
|
static int mixy(PC5Context *ctxpc5, int nn2) {
|
||||||
|
return arc4_output(ctxpc5) % nn2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fisher-Yates shuffle */
|
||||||
|
static void mixer(PC5Context *ctxpc5, uint8_t *mixu, int nn) {
|
||||||
|
int ii, jj, tmmp;
|
||||||
|
for (ii = nn - 1; ii > 0; ii--) {
|
||||||
|
jj = mixy(ctxpc5, ii + 1);
|
||||||
|
tmmp = mixu[jj];
|
||||||
|
mixu[jj] = mixu[ii];
|
||||||
|
mixu[ii] = (uint8_t)tmmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key schedule and S-box generation */
|
||||||
|
void create_keys_pc5(PC5Context *ctxpc5, unsigned char key1[], size_t size1) {
|
||||||
|
int i, w, k;
|
||||||
|
unsigned char h4[n1];
|
||||||
|
|
||||||
|
md2_init(ctxpc5);
|
||||||
|
md2_hashing(ctxpc5, key1, size1);
|
||||||
|
md2_end(ctxpc5, h4);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) ctxpc5->keys[i] = h4[i];
|
||||||
|
arc4_init(ctxpc5, h4);
|
||||||
|
|
||||||
|
ctxpc5->x = 0;
|
||||||
|
for (i = 0; i < 8; i++) ctxpc5->x = (ctxpc5->x << 8) + (uint64_t)(h4[256 + i] & 0xffu);
|
||||||
|
|
||||||
|
ctxpc5->xyz = 0;
|
||||||
|
ctxpc5->count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 23000; i++) (void)arc4_output(ctxpc5);
|
||||||
|
|
||||||
|
uint8_t numbers[256];
|
||||||
|
|
||||||
|
for (w = 0; w < 253; w++) {
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctxpc5, numbers, 16);
|
||||||
|
for (i = 0; i < 16; i++) ctxpc5->perm[i][w] = numbers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctxpc5, numbers, 16);
|
||||||
|
for (i = 0; i < 16; i++) ctxpc5->new1[i] = numbers[i];
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (i = 0; i < nbround; i++) ctxpc5->decal[i] = (uint8_t)((arc4_output(ctxpc5) % 11) + 1);
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (w = 0; w < 3; w++)
|
||||||
|
for (i = 0; i < nbround; i++)
|
||||||
|
ctxpc5->rngxor[i][w] = arc4_output(ctxpc5) % 16;
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (i = 0; i < 16; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctxpc5, numbers, 16);
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
ctxpc5->tab[i] = numbers[i];
|
||||||
|
ctxpc5->inv[ctxpc5->tab[i]] = (unsigned char)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (w = 0; w < 3; w++) {
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (i = 0; i < 3; i++) numbers[i] = (uint8_t)i;
|
||||||
|
mixer(ctxpc5, numbers, 3);
|
||||||
|
for (i = 0; i < 3; i++) ctxpc5->permut[w][i] = numbers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
for (i = 0; i < k; i++) (void)arc4_output(ctxpc5);
|
||||||
|
for (w = 0; w < 3; w++)
|
||||||
|
for (i = 0; i < nbround; i++)
|
||||||
|
ctxpc5->rngxor2[i][w] = arc4_output(ctxpc5) % 16;
|
||||||
|
|
||||||
|
k = arc4_output(ctxpc5) + 256;
|
||||||
|
|
||||||
|
for (w = 0; w < 25; w++) ctxpc5->numbers[w]=arc4_output(ctxpc5) % 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compute_pc5(PC5Context *ctxpc5, uint8_t *tab1, uint8_t round) {
|
||||||
|
ctxpc5->tot[0] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[0][0]]][round] +
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[0][1]]][round]) ^
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[0][2]]][round]);
|
||||||
|
ctxpc5->tot[0] = (uint8_t)((ctxpc5->tot[0] + ctxpc5->new1[ctxpc5->tot[0]]) % 16);
|
||||||
|
ctxpc5->tot[1] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[1][0]]][round] +
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[1][1]]][round]) ^
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[1][2]]][round]);
|
||||||
|
ctxpc5->tot[1] = (uint8_t)((ctxpc5->tot[1] + ctxpc5->new1[ctxpc5->tot[1]]) % 16);
|
||||||
|
ctxpc5->tot[2] = (uint8_t)((ctxpc5->perm[tab1[ctxpc5->permut[2][0]]][round] +
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[2][1]]][round]) ^
|
||||||
|
ctxpc5->perm[tab1[ctxpc5->permut[2][2]]][round]);
|
||||||
|
ctxpc5->tot[2] = (uint8_t)((ctxpc5->tot[2] + ctxpc5->new1[ctxpc5->tot[2]]) % 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert bits to bytes */
|
||||||
|
void binhexpc5(PC5Context *ctxpc5, short *z, int length) {
|
||||||
|
short *b = (short *)z;
|
||||||
|
uint8_t i, j;
|
||||||
|
for (i = 0; i < length; i = j) {
|
||||||
|
uint8_t a = 0;
|
||||||
|
for (j = i; j < i + 8; ++j) {
|
||||||
|
a |= (uint8_t)(b[((short)(7 - (j % 8)) + j) - (j % 8)] << (j - i));
|
||||||
|
}
|
||||||
|
ctxpc5->convert[ctxpc5->ptconvert] = a;
|
||||||
|
ctxpc5->ptconvert++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert byte to bits */
|
||||||
|
void hexbinpc5(PC5Context *ctxpc5, short *q, uint8_t w, uint8_t hex) { // warning: unused parameter ‘ctxpc5’ [-Wunused-parameter]
|
||||||
|
UNUSED(ctxpc5);
|
||||||
|
short *bits = (short *)q;
|
||||||
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
|
bits[(short)(7 + w) - i] = (short)((hex >> i) & 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNUSEDPC4(ctxpc5); //fix above warning
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encrypt one block */
|
||||||
|
void pc5encrypt(PC5Context *ctxpc5) {
|
||||||
|
int i;
|
||||||
|
int g;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctxpc5->l[0][i] = ctxpc5->convert[i];
|
||||||
|
ctxpc5->r[0][i] = ctxpc5->convert[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; i <= ctxpc5->rounds; i++) {
|
||||||
|
ctxpc5->r[(i - 1) % 2][0] = (ctxpc5->r[(i - 1) % 2][0] + ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][0])) % 16;
|
||||||
|
ctxpc5->r[(i - 1) % 2][1] = (ctxpc5->r[(i - 1) % 2][1] ^ ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][1])) % 16;
|
||||||
|
ctxpc5->r[(i - 1) % 2][2] = (ctxpc5->r[(i - 1) % 2][2] + ((uint8_t)~ctxpc5->rngxor2[ctxpc5->rounds - i][2])) % 16;
|
||||||
|
|
||||||
|
ctxpc5->result = 0;
|
||||||
|
ctxpc5->result += ((uint32_t)ctxpc5->r[(i - 1) % 2][0] << 8);
|
||||||
|
ctxpc5->result += ((uint32_t)ctxpc5->r[(i - 1) % 2][1] << 4);
|
||||||
|
ctxpc5->result += ctxpc5->r[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctxpc5->result = rol(ctxpc5->result, ctxpc5->decal[i - 1], 12);
|
||||||
|
|
||||||
|
ctxpc5->r[(i - 1) % 2][0] = (uint8_t)(ctxpc5->result >> 8);
|
||||||
|
ctxpc5->r[(i - 1) % 2][1] = (uint8_t)((ctxpc5->result >> 4) & 0xfu);
|
||||||
|
ctxpc5->r[(i - 1) % 2][2] = (uint8_t)(ctxpc5->result & 0xfu);
|
||||||
|
|
||||||
|
ctxpc5->r[(i - 1) % 2][0] = ctxpc5->tab[ctxpc5->r[(i - 1) % 2][0]];
|
||||||
|
ctxpc5->r[(i - 1) % 2][0] = (ctxpc5->r[(i - 1) % 2][0] ^ ctxpc5->rngxor[i - 1][0]) % 16;
|
||||||
|
|
||||||
|
ctxpc5->r[(i - 1) % 2][1] = ctxpc5->inv[ctxpc5->r[(i - 1) % 2][1]];
|
||||||
|
|
||||||
|
if ((ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) < 0) {
|
||||||
|
g = (ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) + 16;
|
||||||
|
} else {
|
||||||
|
g = (ctxpc5->r[(i - 1) % 2][1] - ctxpc5->rngxor[i - 1][1]) % 16;
|
||||||
|
}
|
||||||
|
ctxpc5->r[(i - 1) % 2][1] = g;
|
||||||
|
|
||||||
|
ctxpc5->r[(i - 1) % 2][2] = ctxpc5->tab[ctxpc5->r[(i - 1) % 2][2]];
|
||||||
|
ctxpc5->r[(i - 1) % 2][2] = (ctxpc5->r[(i - 1) % 2][2] ^ ctxpc5->rngxor[i - 1][2]) % 16;
|
||||||
|
|
||||||
|
compute_pc5(ctxpc5, ctxpc5->r[(i - 1) % 2], (uint8_t)((i - 1) % 253));
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][0] = ctxpc5->r[(i - 1) % 2][0];
|
||||||
|
|
||||||
|
if ((ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0]) < 0) {
|
||||||
|
g = (ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0]) + 16;
|
||||||
|
} else {
|
||||||
|
g = ctxpc5->l[(i - 1) % 2][0] - ctxpc5->tot[0];
|
||||||
|
}
|
||||||
|
ctxpc5->r[i % 2][0] = g;
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][1] = ctxpc5->r[(i - 1) % 2][1];
|
||||||
|
ctxpc5->r[i % 2][1] = (ctxpc5->l[(i - 1) % 2][1] ^ ctxpc5->tot[1]) % 16;
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][2] = ctxpc5->r[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
if ((ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2]) < 0) {
|
||||||
|
g = (ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2]) + 16;
|
||||||
|
} else {
|
||||||
|
g = ctxpc5->l[(i - 1) % 2][2] - ctxpc5->tot[2];
|
||||||
|
}
|
||||||
|
ctxpc5->r[i % 2][2] = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctxpc5->convert[i + 3] = ctxpc5->l[(ctxpc5->rounds - 1) % 2][i];
|
||||||
|
ctxpc5->convert[i] = ctxpc5->r[(ctxpc5->rounds - 1) % 2][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrypt one block */
|
||||||
|
void pc5decrypt(PC5Context *ctxpc5) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctxpc5->l[0][i] = ctxpc5->convert[i];
|
||||||
|
ctxpc5->r[0][i] = ctxpc5->convert[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxpc5->y = (uint8_t)((ctxpc5->rounds - 1) % 253);
|
||||||
|
if (ctxpc5->y == 0) ctxpc5->y = 253;
|
||||||
|
|
||||||
|
for (i = 1; i <= ctxpc5->rounds; i++) {
|
||||||
|
ctxpc5->y--;
|
||||||
|
compute_pc5(ctxpc5, ctxpc5->r[(i - 1) % 2], ctxpc5->y);
|
||||||
|
if (ctxpc5->y == 0) ctxpc5->y = 253;
|
||||||
|
|
||||||
|
ctxpc5->result = 0;
|
||||||
|
|
||||||
|
ctxpc5->l[(i - 1) % 2][0] ^= ctxpc5->rngxor[ctxpc5->rounds - i][0];
|
||||||
|
ctxpc5->l[(i - 1) % 2][0] %= 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][0] = ctxpc5->inv[ctxpc5->l[(i - 1) % 2][0]];
|
||||||
|
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] += ctxpc5->rngxor[ctxpc5->rounds - i][1];
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] %= 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] = ctxpc5->tab[ctxpc5->l[(i - 1) % 2][1]];
|
||||||
|
|
||||||
|
ctxpc5->l[(i - 1) % 2][2] ^= ctxpc5->rngxor[ctxpc5->rounds - i][2];
|
||||||
|
ctxpc5->l[(i - 1) % 2][2] %= 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][2] = ctxpc5->inv[ctxpc5->l[(i - 1) % 2][2]];
|
||||||
|
|
||||||
|
ctxpc5->result += ((uint32_t)ctxpc5->l[(i - 1) % 2][0] << 8);
|
||||||
|
ctxpc5->result += ((uint32_t)ctxpc5->l[(i - 1) % 2][1] << 4);
|
||||||
|
ctxpc5->result += ctxpc5->l[(i - 1) % 2][2];
|
||||||
|
|
||||||
|
ctxpc5->result = ror(ctxpc5->result, ctxpc5->decal[ctxpc5->rounds - i], 12);
|
||||||
|
|
||||||
|
ctxpc5->l[(i - 1) % 2][0] = (uint8_t)(ctxpc5->result >> 8);
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] = (uint8_t)((ctxpc5->result >> 4) & 0xfu);
|
||||||
|
ctxpc5->l[(i - 1) % 2][2] = (uint8_t)(ctxpc5->result & 0xfu);
|
||||||
|
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
temp = ctxpc5->l[(i - 1) % 2][0] - ((uint8_t)(~ctxpc5->rngxor2[i - 1][0]) % 16);
|
||||||
|
if (temp < 0) temp += 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][0] = temp % 16;
|
||||||
|
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] ^= (uint8_t)(~ctxpc5->rngxor2[i - 1][1]) % 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][1] %= 16;
|
||||||
|
|
||||||
|
temp = ctxpc5->l[(i - 1) % 2][2] - ((uint8_t)(~ctxpc5->rngxor2[i - 1][2]) % 16);
|
||||||
|
if (temp < 0) temp += 16;
|
||||||
|
ctxpc5->l[(i - 1) % 2][2] = temp % 16;
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][0] = ctxpc5->r[(i - 1) % 2][0];
|
||||||
|
ctxpc5->r[i % 2][0] = (ctxpc5->l[(i - 1) % 2][0] + ctxpc5->tot[0]) % 16;
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][1] = ctxpc5->r[(i - 1) % 2][1];
|
||||||
|
ctxpc5->r[i % 2][1] = (ctxpc5->l[(i - 1) % 2][1] ^ ctxpc5->tot[1]) % 16;
|
||||||
|
|
||||||
|
ctxpc5->l[i % 2][2] = ctxpc5->r[(i - 1) % 2][2];
|
||||||
|
ctxpc5->r[i % 2][2] = (ctxpc5->l[(i - 1) % 2][2] + ctxpc5->tot[2]) % 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
ctxpc5->convert[i + 3] = ctxpc5->l[(ctxpc5->rounds - 1) % 2][i];
|
||||||
|
ctxpc5->convert[i] = ctxpc5->r[(ctxpc5->rounds - 1) % 2][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key creation for BAOFENG AP */
|
||||||
|
void baofeng_ap_pc5_keystream_creation(dsd_state *state, char *input) {
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
strncpy(buf, input, sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
|
||||||
|
// Count hexadecimal characters (without spaces)
|
||||||
|
int hex_char_count = 0;
|
||||||
|
for (int i = 0; buf[i] != '\0'; i++) {
|
||||||
|
if (isxdigit(buf[i])) {
|
||||||
|
hex_char_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex_char_count == 32) { // 128 bits (32 hex characters)
|
||||||
|
unsigned char key1[16] = {0};
|
||||||
|
unsigned char key2[16] = {0};
|
||||||
|
|
||||||
|
char *pEnd;
|
||||||
|
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||||
|
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
|
||||||
|
u64_to_bytes_be_pc5(K1, &key1[0]);
|
||||||
|
u64_to_bytes_be_pc5(K2, &key1[8]);
|
||||||
|
|
||||||
|
// Reverse key for PC5 (only for 128-bit)
|
||||||
|
for (int i=0;i<16;i++) key2[i] = key1[15-i];
|
||||||
|
|
||||||
|
/* Create key schedule */
|
||||||
|
create_keys_pc5(&ctxpc5, key2, sizeof(key2));
|
||||||
|
ctxpc5.rounds = nbround;
|
||||||
|
|
||||||
|
fprintf(stderr, "DMR BAOFENG AP (PC5) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||||
|
(unsigned long long)K1, (unsigned long long)K2);
|
||||||
|
state->baofeng_ap = 1;
|
||||||
|
|
||||||
|
} else if (hex_char_count == 64) { // 256 bits (64 hex characters)
|
||||||
|
// Remove spaces and store as ASCII string (64 bytes)
|
||||||
|
char ascii_key[65] = {0}; // 64 characters + null terminator
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; buf[i] != '\0' && j < 64; i++) {
|
||||||
|
if (isxdigit(buf[i])) {
|
||||||
|
ascii_key[j++] = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ascii_key[64] = '\0';
|
||||||
|
|
||||||
|
/* Create key schedule */
|
||||||
|
create_keys_pc5(&ctxpc5, (unsigned char*)ascii_key, 64);
|
||||||
|
ctxpc5.rounds = nbround;
|
||||||
|
|
||||||
|
fprintf(stderr, "DMR BAOFENG AP (PC5) 256-bit Key: %s with Forced Application\n", ascii_key);
|
||||||
|
state->baofeng_ap = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Invalid key length. Expected 32 chars (128-bit) or 64 chars (256-bit), got %d hex chars\n", hex_char_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
404
src/crypt-rc2.c
Normal file
404
src/crypt-rc2.c
Normal file
@@ -0,0 +1,404 @@
|
|||||||
|
#include "rc2.h"
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
static inline uint64_t rol64(uint64_t x, int n) {
|
||||||
|
return ((x << n) | (x >> (63 - n) >> 1)) & 0xffffffffffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapbit(uint64_t* internalstate, uint8_t bit) {
|
||||||
|
unsigned char bitB = bit & 1;
|
||||||
|
if (bitB)
|
||||||
|
*internalstate |= bitB;
|
||||||
|
else
|
||||||
|
*internalstate &= (~bitB ^ 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD2 functions
|
||||||
|
void md2_init(MD2State* state) {
|
||||||
|
state->x1 = 0;
|
||||||
|
state->x2 = 0;
|
||||||
|
memset(state->h2, 0, n1);
|
||||||
|
memset(state->h1, 0, n1 * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void md2_hashing(MD2State* state, unsigned char t1[], size_t b6) {
|
||||||
|
static unsigned char s4[256] = {
|
||||||
|
13,199,11,67,237,193,164,77,115,184,141,222,73,
|
||||||
|
38,147,36,150,87,21,104,12,61,156,101,111,145,
|
||||||
|
119,22,207,35,198,37,171,167,80,30,219,28,213,
|
||||||
|
121,86,29,214,242,6,4,89,162,110,175,19,157,
|
||||||
|
3,88,234,94,144,118,159,239,100,17,182,173,238,
|
||||||
|
68,16,79,132,54,163,52,9,58,57,55,229,192,
|
||||||
|
170,226,56,231,187,158,70,224,233,245,26,47,32,
|
||||||
|
44,247,8,251,20,197,185,109,153,204,218,93,178,
|
||||||
|
212,137,84,174,24,120,130,149,72,180,181,208,255,
|
||||||
|
189,152,18,143,176,60,249,27,227,128,139,243,253,
|
||||||
|
59,123,172,108,211,96,138,10,215,42,225,40,81,
|
||||||
|
65,90,25,98,126,154,64,124,116,122,5,1,168,
|
||||||
|
83,190,131,191,244,240,235,177,155,228,125,66,43,
|
||||||
|
201,248,220,129,188,230,62,75,71,78,34,31,216,
|
||||||
|
254,136,91,114,106,46,217,196,92,151,209,133,51,
|
||||||
|
236,33,252,127,179,69,7,183,105,146,97,39,15,
|
||||||
|
205,112,200,166,223,45,48,246,186,41,148,140,107,
|
||||||
|
76,85,95,194,142,50,49,134,23,135,169,221,210,
|
||||||
|
203,63,165,82,161,202,53,14,206,232,103,102,195,
|
||||||
|
117,250,99,0,74,160,241,2,113
|
||||||
|
};
|
||||||
|
|
||||||
|
int b4 = 0;
|
||||||
|
|
||||||
|
while (b6) {
|
||||||
|
for (; b6 && state->x2 < n1; b6--, state->x2++) {
|
||||||
|
int b5 = t1[b4++];
|
||||||
|
state->h1[state->x2 + n1] = b5;
|
||||||
|
state->h1[state->x2 + (n1 * 2)] = b5 ^ state->h1[state->x2];
|
||||||
|
state->x1 = state->h2[state->x2] ^= s4[b5 ^ state->x1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->x2 == n1) {
|
||||||
|
int b2 = 0;
|
||||||
|
state->x2 = 0;
|
||||||
|
|
||||||
|
for (int b3 = 0; b3 < (n1 + 2); b3++) {
|
||||||
|
for (int b1 = 0; b1 < (n1 * 3); b1++)
|
||||||
|
b2 = state->h1[b1] ^= s4[b2];
|
||||||
|
b2 = (b2 + b3) % 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void md2_end(MD2State* state, unsigned char h4[n1]) {
|
||||||
|
unsigned char h3[n1];
|
||||||
|
int n4 = n1 - state->x2;
|
||||||
|
for (int i = 0; i < n4; i++) h3[i] = n4;
|
||||||
|
md2_hashing(state, h3, n4);
|
||||||
|
md2_hashing(state, state->h2, sizeof(state->h2));
|
||||||
|
for (int i = 0; i < n1; i++) h4[i] = state->h1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// RC4 functions
|
||||||
|
uint64_t next(RC4State* state) {
|
||||||
|
uint64_t z = (state->x += 0x9e3779b97f4a7c15);
|
||||||
|
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||||
|
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||||
|
return z ^ (z >> 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc4_init(RC4State* state, unsigned char key[]) {
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||||
|
state->array_rc4[state->i_rc4] = state->i_rc4;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->j_rc4 = 0;
|
||||||
|
for (state->i_rc4 = 0; state->i_rc4 < 256; state->i_rc4++) {
|
||||||
|
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4] + key[state->i_rc4 % 256]) % 256;
|
||||||
|
tmp = state->array_rc4[state->i_rc4];
|
||||||
|
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||||
|
state->array_rc4[state->j_rc4] = tmp;
|
||||||
|
}
|
||||||
|
state->i_rc4 = 0;
|
||||||
|
state->j_rc4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char rc4_output(RC4State* state) {
|
||||||
|
uint8_t rndbyte, decal;
|
||||||
|
int tmp, t;
|
||||||
|
|
||||||
|
state->i_rc4 = (state->i_rc4 + 1) % 256;
|
||||||
|
state->j_rc4 = (state->j_rc4 + state->array_rc4[state->i_rc4]) % 256;
|
||||||
|
tmp = state->array_rc4[state->i_rc4];
|
||||||
|
state->array_rc4[state->i_rc4] = state->array_rc4[state->j_rc4];
|
||||||
|
state->array_rc4[state->j_rc4] = tmp;
|
||||||
|
t = (state->array_rc4[state->i_rc4] + state->array_rc4[state->j_rc4]) % 256;
|
||||||
|
|
||||||
|
|
||||||
|
if (state->xyz == 0) state->bb = next(state);
|
||||||
|
decal = 56 - (8 * state->xyz);
|
||||||
|
rndbyte = (state->bb >> decal) & 0xff;
|
||||||
|
state->xyz++;
|
||||||
|
if (state->xyz == 8) state->xyz = 0;
|
||||||
|
|
||||||
|
if (state->count == 0) {
|
||||||
|
rndbyte = rndbyte ^ state->array_rc4[t];
|
||||||
|
state->count = 1;
|
||||||
|
} else {
|
||||||
|
rndbyte = rndbyte + state->array_rc4[t];
|
||||||
|
state->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rndbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert 64-bit integer to bytes (big-endian) */
|
||||||
|
static void u64_to_bytes_be(uint64_t val, unsigned char *out) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
out[i] = (unsigned char)((val >> (56 - 8 * i)) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RC2 functions
|
||||||
|
void rc2_keyschedule(RC2State* state) {
|
||||||
|
unsigned i;
|
||||||
|
// Phase 3 - copy to xkey in little-endian order
|
||||||
|
i = 63;
|
||||||
|
do {
|
||||||
|
state->xkey[i] = ((unsigned char *)state->xkey)[2 * i] +
|
||||||
|
(((unsigned char *)state->xkey)[2 * i + 1] << 8);
|
||||||
|
} while (i--);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc2_encrypt(RC2State* state) {
|
||||||
|
uint16_t x76, x54, x32, x10, i;
|
||||||
|
|
||||||
|
x76 = (state->plain[7] << 8) + state->plain[6];
|
||||||
|
x54 = (state->plain[5] << 8) + state->plain[4];
|
||||||
|
x32 = (state->plain[3] << 8) + state->plain[2];
|
||||||
|
x10 = (state->plain[1] << 8) + state->plain[0];
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
x10 += (x32 & ~x76) + (x54 & x76) + state->xkey[4 * i + 0];
|
||||||
|
x10 = (x10 << 1) + (x10 >> 15 & 1);
|
||||||
|
|
||||||
|
x32 += (x54 & ~x10) + (x76 & x10) + state->xkey[4 * i + 1];
|
||||||
|
x32 = (x32 << 2) + (x32 >> 14 & 3);
|
||||||
|
|
||||||
|
x54 += (x76 & ~x32) + (x10 & x32) + state->xkey[4 * i + 2];
|
||||||
|
x54 = (x54 << 3) + (x54 >> 13 & 7);
|
||||||
|
|
||||||
|
x76 += (x10 & ~x54) + (x32 & x54) + state->xkey[4 * i + 3];
|
||||||
|
x76 = (x76 << 5) + (x76 >> 11 & 31);
|
||||||
|
|
||||||
|
if (i == 4 || i == 10) {
|
||||||
|
x10 += state->xkey[x76 & 63];
|
||||||
|
x32 += state->xkey[x10 & 63];
|
||||||
|
x54 += state->xkey[x32 & 63];
|
||||||
|
x76 += state->xkey[x54 & 63];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state->cipher[0] = (unsigned char)x10;
|
||||||
|
state->cipher[1] = (unsigned char)(x10 >> 8);
|
||||||
|
state->cipher[2] = (unsigned char)x32;
|
||||||
|
state->cipher[3] = (unsigned char)(x32 >> 8);
|
||||||
|
state->cipher[4] = (unsigned char)x54;
|
||||||
|
state->cipher[5] = (unsigned char)(x54 >> 8);
|
||||||
|
state->cipher[6] = (unsigned char)x76;
|
||||||
|
state->cipher[7] = (unsigned char)(x76 >> 8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main cryptographic functions
|
||||||
|
void create_keys_rc2(CryptoContext* ctx, unsigned char key1[], size_t size1) {
|
||||||
|
unsigned char h4[n1];
|
||||||
|
|
||||||
|
// Initialize MD2 and hash the key
|
||||||
|
md2_init(&ctx->md2);
|
||||||
|
md2_hashing(&ctx->md2, key1, size1);
|
||||||
|
md2_end(&ctx->md2, h4);
|
||||||
|
|
||||||
|
// Copy first 16 bytes to keys
|
||||||
|
for (int i = 0; i < 16; i++) ctx->keys[i] = h4[i];
|
||||||
|
|
||||||
|
// Initialize RC4 with hashed key
|
||||||
|
rc4_init(&ctx->rc4, h4);
|
||||||
|
|
||||||
|
// Initialize RC4 state variables
|
||||||
|
ctx->rc4.x = 0;
|
||||||
|
for (int i = 0; i < 8; i++) ctx->rc4.x = (ctx->rc4.x << 8) + (h4[256 + i] & 0xff);
|
||||||
|
|
||||||
|
ctx->rc4.xyz = 0;
|
||||||
|
ctx->rc4.count = 0;
|
||||||
|
|
||||||
|
// Warm-up RC4
|
||||||
|
for (int i = 0; i < 22000; i++) rc4_output(&ctx->rc4);
|
||||||
|
|
||||||
|
// Generate RC2 keys
|
||||||
|
int k = rc4_output(&ctx->rc4) + 256;
|
||||||
|
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
ctx->rc2.xkey[i] = (rc4_output(&ctx->rc4) << 8) + rc4_output(&ctx->rc4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate internal zero value
|
||||||
|
k = rc4_output(&ctx->rc4) + 256;
|
||||||
|
for (int i = 0; i < k; i++) rc4_output(&ctx->rc4);
|
||||||
|
|
||||||
|
ctx->internal_zero = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ctx->internal_zero = (ctx->internal_zero << 8) + rc4_output(&ctx->rc4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate RC2 key schedule
|
||||||
|
rc2_keyschedule(&ctx->rc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void encryption_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||||
|
ctx->internal_state = ctx->internal_zero;
|
||||||
|
|
||||||
|
for (int sso = 0; sso < 49; sso++) {
|
||||||
|
// Prepare plaintext from internal state
|
||||||
|
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||||
|
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||||
|
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||||
|
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||||
|
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||||
|
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||||
|
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||||
|
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||||
|
|
||||||
|
// Encrypt with RC2
|
||||||
|
rc2_encrypt(&ctx->rc2);
|
||||||
|
|
||||||
|
// Reconstruct internal state from ciphertext
|
||||||
|
ctx->internal_state = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR the bit and update internal state
|
||||||
|
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||||
|
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||||
|
swapbit(&ctx->internal_state, bits[48 - sso]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void decrypt_rc2(CryptoContext* ctx, uint8_t bits[49]) {
|
||||||
|
uint8_t tempy;
|
||||||
|
ctx->internal_state = ctx->internal_zero;
|
||||||
|
|
||||||
|
|
||||||
|
for (int sso = 0; sso < 49; sso++) {
|
||||||
|
// Prepare plaintext from internal state
|
||||||
|
ctx->rc2.plain[0] = (ctx->internal_state >> 56) & 0xff;
|
||||||
|
ctx->rc2.plain[1] = (ctx->internal_state >> 48) & 0xff;
|
||||||
|
ctx->rc2.plain[2] = (ctx->internal_state >> 40) & 0xff;
|
||||||
|
ctx->rc2.plain[3] = (ctx->internal_state >> 32) & 0xff;
|
||||||
|
ctx->rc2.plain[4] = (ctx->internal_state >> 24) & 0xff;
|
||||||
|
ctx->rc2.plain[5] = (ctx->internal_state >> 16) & 0xff;
|
||||||
|
ctx->rc2.plain[6] = (ctx->internal_state >> 8) & 0xff;
|
||||||
|
ctx->rc2.plain[7] = ctx->internal_state & 0xff;
|
||||||
|
|
||||||
|
// Encrypt with RC2
|
||||||
|
rc2_encrypt(&ctx->rc2);
|
||||||
|
|
||||||
|
// Reconstruct internal state from ciphertext
|
||||||
|
ctx->internal_state = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ctx->internal_state = (ctx->internal_state << 8) + (ctx->rc2.cipher[i] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR the bit and update internal state
|
||||||
|
tempy = bits[48 - sso];
|
||||||
|
bits[48 - sso] = bits[48 - sso] ^ (ctx->internal_state & 1);
|
||||||
|
ctx->internal_state = rol64(ctx->internal_state, 1);
|
||||||
|
swapbit(&ctx->internal_state, tempy);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key creation for Retevis AP */
|
||||||
|
void retevis_rc2_keystream_creation(dsd_state *state, char *input) {
|
||||||
|
|
||||||
|
unsigned char key1[64]; memset(key1, 0, sizeof(key1));
|
||||||
|
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
strncpy(buf, input, sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
|
||||||
|
char *pEnd;
|
||||||
|
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||||
|
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
uint64_t K3 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
uint64_t K4 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
|
||||||
|
if (K3 != 0 || K4 != 0) //256-bit keys loaded as ASCII characters
|
||||||
|
{
|
||||||
|
//start loading K1, K2, K3, and K4 as ASCII to fill 64 bytes of key1
|
||||||
|
int k = 0; uint8_t x = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K1 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K2 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K3 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K4 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "ASCII: ");
|
||||||
|
// for (int i = 0; i < 64; i++)
|
||||||
|
// fprintf (stderr, " %02X", key1[i]);
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
// Initialize RC2 context
|
||||||
|
static CryptoContext rc2_ctx;
|
||||||
|
create_keys_rc2(&rc2_ctx, key1, 64);
|
||||||
|
|
||||||
|
// Store context in DSD state
|
||||||
|
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||||
|
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||||
|
|
||||||
|
fprintf(stderr, "DMR RETEVIS AP (RC2) 256-bit Key %016llX%016llX%016llX%016llX with Forced Application\n",
|
||||||
|
(unsigned long long)K1, (unsigned long long)K2, (unsigned long long)K3, (unsigned long long)K4);
|
||||||
|
|
||||||
|
state->retevis_ap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else //128-bit loaded as reverse bytes
|
||||||
|
{
|
||||||
|
|
||||||
|
u64_to_bytes_be(K1, &key1[0]);
|
||||||
|
u64_to_bytes_be(K2, &key1[8]);
|
||||||
|
|
||||||
|
// reverse load the key bytes into key2
|
||||||
|
for (int i=0;i<16;i++)
|
||||||
|
key2[i] = key1[15-i];
|
||||||
|
|
||||||
|
// Initialize RC2 context
|
||||||
|
static CryptoContext rc2_ctx;
|
||||||
|
create_keys_rc2(&rc2_ctx, key2, 16);
|
||||||
|
|
||||||
|
// Store context in DSD state
|
||||||
|
state->rc2_context = malloc(sizeof(CryptoContext));
|
||||||
|
memcpy(state->rc2_context, &rc2_ctx, sizeof(CryptoContext));
|
||||||
|
|
||||||
|
fprintf(stderr, "DMR RETEVIS AP (RC2) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||||
|
(unsigned long long)K1, (unsigned long long)K2);
|
||||||
|
|
||||||
|
state->retevis_ap = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
146
src/crypt-rc4.c
Normal file
146
src/crypt-rc4.c
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* rc4.c Crypthings
|
||||||
|
* RC4 Alg
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
//this version is for voice, going to transition to a block output version
|
||||||
|
void rc4_voice_decrypt(int drop, uint8_t keylength, uint8_t messagelength, uint8_t key[], uint8_t cipher[], uint8_t plain[])
|
||||||
|
{
|
||||||
|
int i, j, count;
|
||||||
|
uint8_t t, b;
|
||||||
|
|
||||||
|
//init Sbox
|
||||||
|
uint8_t S[256];
|
||||||
|
for(int i = 0; i < 256; i++) S[i] = i;
|
||||||
|
|
||||||
|
//Key Scheduling
|
||||||
|
j = 0;
|
||||||
|
for(i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
j = (j + S[i] + key[i % keylength]) % 256;
|
||||||
|
t = S[i];
|
||||||
|
S[i] = S[j];
|
||||||
|
S[j] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Drop Bytes and Cipher Byte XOR
|
||||||
|
i = j = 0;
|
||||||
|
for(count = 0; count < (messagelength + drop); count++)
|
||||||
|
{
|
||||||
|
i = (i + 1) % 256;
|
||||||
|
j = (j + S[i]) % 256;
|
||||||
|
t = S[i];
|
||||||
|
S[i] = S[j];
|
||||||
|
S[j] = t;
|
||||||
|
b = S[(S[i] + S[j]) % 256];
|
||||||
|
|
||||||
|
//return mbe payload byte here
|
||||||
|
if (count >= drop)
|
||||||
|
plain[count - drop] = b^cipher[count - drop];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is for PDU usage
|
||||||
|
void rc4_block_output (int drop, int keylen, int meslen, uint8_t * key, uint8_t * output_blocks)
|
||||||
|
{
|
||||||
|
int i, j, x, count;
|
||||||
|
unsigned int keylength = (unsigned int)keylen;
|
||||||
|
unsigned int messagelength = (unsigned int)meslen;
|
||||||
|
unsigned int S[256];
|
||||||
|
|
||||||
|
for(i=0; i<256; i++)
|
||||||
|
S[i] = i;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for(i = 0; i<256; i++)
|
||||||
|
{
|
||||||
|
j = (j + S[i] + key[i % keylength]) % 256;
|
||||||
|
unsigned int temp = S[i];
|
||||||
|
S[i] = S[j];
|
||||||
|
S[j] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate Keystream
|
||||||
|
i = 0;
|
||||||
|
j = 0;
|
||||||
|
x = 0;
|
||||||
|
unsigned int byte;
|
||||||
|
|
||||||
|
// fprintf (stderr, " Keystream Octets = ");
|
||||||
|
for(count = 0; count < (messagelength + drop); count++)
|
||||||
|
{
|
||||||
|
i = (i + 1) % 256;
|
||||||
|
j = (j + S[i]) % 256;
|
||||||
|
unsigned int temp = S[i];
|
||||||
|
S[i] = S[j];
|
||||||
|
S[j] = temp;
|
||||||
|
byte = S[(S[i] + S[j]) % 256];
|
||||||
|
|
||||||
|
//Collect Output blocks
|
||||||
|
if (count >= drop)
|
||||||
|
output_blocks[x++] = byte;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is now verified to work after changing the drop byte value from 256 to 0.
|
||||||
|
//also, had to change the application to not skip the additional 7 bits like DMRA or P25 does.
|
||||||
|
void hytera_enhanced_rc4_setup(dsd_opts * opts, dsd_state * state, unsigned long long int key_value, unsigned long long int mi_value)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
uint8_t key[5]; memset (key, 0, sizeof(key));
|
||||||
|
uint8_t kiv[5]; memset (kiv, 0, sizeof(kiv));
|
||||||
|
uint8_t mi[5]; memset (mi, 0, sizeof(mi));
|
||||||
|
uint8_t ks[135]; memset (ks, 0, sizeof(ks));
|
||||||
|
|
||||||
|
//load key_value into key array
|
||||||
|
key[0] = ((key_value & 0xFF00000000) >> 32UL);
|
||||||
|
key[1] = ((key_value & 0xFF000000) >> 24);
|
||||||
|
key[2] = ((key_value & 0xFF0000) >> 16);
|
||||||
|
key[3] = ((key_value & 0xFF00) >> 8);
|
||||||
|
key[4] = ((key_value & 0xFF) >> 0);
|
||||||
|
|
||||||
|
//load mi_value into mi array
|
||||||
|
mi[0] = ((mi_value & 0xFF00000000) >> 32UL);
|
||||||
|
mi[1] = ((mi_value & 0xFF000000) >> 24);
|
||||||
|
mi[2] = ((mi_value & 0xFF0000) >> 16);
|
||||||
|
mi[3] = ((mi_value & 0xFF00) >> 8);
|
||||||
|
mi[4] = ((mi_value & 0xFF) >> 0);
|
||||||
|
|
||||||
|
//pointer to the ks_octet storage
|
||||||
|
uint8_t * ks_octets;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
ks_octets = state->ks_octetL;
|
||||||
|
else ks_octets = state->ks_octetR;
|
||||||
|
|
||||||
|
//NOTE: Drop Byte value is 0
|
||||||
|
rc4_block_output(0, 5, 135, key, ks);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
kiv[i] = key[i] ^ mi[i];
|
||||||
|
|
||||||
|
for (int i = 0; i < 135; i++)
|
||||||
|
ks_octets[i] = kiv[i%5] ^ ks[i];
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " KS: ");
|
||||||
|
// for (int i = 0; i < 135; i++)
|
||||||
|
// {
|
||||||
|
// if ((i != 0) && ((i%7) == 0))
|
||||||
|
// fprintf (stderr, " ");
|
||||||
|
// fprintf (stderr, "%02X", ks[i]); //ks_octets
|
||||||
|
// }
|
||||||
|
|
||||||
|
//NULL pointer to ks_octets
|
||||||
|
ks_octets = NULL;
|
||||||
|
|
||||||
|
//end line break
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
}
|
||||||
361
src/crypt-tyt.c
Normal file
361
src/crypt-tyt.c
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
#include "dsd.h"
|
||||||
|
#include "dmr_const.h"
|
||||||
|
#include "pc4.h"
|
||||||
|
|
||||||
|
//interleaved code words for AMBE+2 (as it arrives over the air)
|
||||||
|
void ambe2_codeword_print_i (dsd_opts * opts, char ambe_fr[4][24])
|
||||||
|
{
|
||||||
|
uint8_t interleaved[72];
|
||||||
|
memset (interleaved, 0, sizeof(interleaved));
|
||||||
|
|
||||||
|
//reinterleave the frame
|
||||||
|
const int *w, *x, *y, *z;
|
||||||
|
w = rW; x = rX; y = rY; z = rZ;
|
||||||
|
|
||||||
|
for (int8_t i = 0; i < 36; i++)
|
||||||
|
{
|
||||||
|
interleaved[(i*2)+0] = (uint8_t)ambe_fr[*w][*x];
|
||||||
|
interleaved[(i*2)+1] = (uint8_t)ambe_fr[*y][*z];
|
||||||
|
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bytes[9]; memset(bytes, 0, sizeof(bytes));
|
||||||
|
|
||||||
|
//pack
|
||||||
|
pack_bit_array_into_byte_array(interleaved, bytes, 9);
|
||||||
|
|
||||||
|
if (opts->payload == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AMBE HEX(72) INT: ");
|
||||||
|
for (int8_t i = 0; i < 9; i++)
|
||||||
|
fprintf (stderr, "%02X", bytes[i]);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//de-interleaved code words for AMBE+2
|
||||||
|
void ambe2_codeword_print_b (dsd_opts * opts, char ambe_fr[4][24])
|
||||||
|
{
|
||||||
|
uint8_t fr_reverse[4][24]; memset(fr_reverse, 0, sizeof(fr_reverse));
|
||||||
|
for (int i = 0; i < 24; i++)
|
||||||
|
fr_reverse[0][i] = ambe_fr[0][23-i];
|
||||||
|
for (int i = 0; i < 23; i++)
|
||||||
|
fr_reverse[1][i] = ambe_fr[1][22-i];
|
||||||
|
for (int i = 0; i < 11; i++)
|
||||||
|
fr_reverse[2][i] = ambe_fr[2][10-i];
|
||||||
|
for (int i = 0; i < 14; i++)
|
||||||
|
fr_reverse[3][i] = ambe_fr[3][13-i];
|
||||||
|
|
||||||
|
uint32_t v0 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[0], 24); //24
|
||||||
|
uint32_t v1 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[1], 23); //23
|
||||||
|
uint32_t v2 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[2], 11); //11
|
||||||
|
uint32_t v3 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[3], 14); //14
|
||||||
|
|
||||||
|
uint32_t c0 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[0], 12);
|
||||||
|
uint32_t c1 = (uint32_t)convert_bits_into_output((uint8_t *)fr_reverse[1], 12);
|
||||||
|
|
||||||
|
//72 bit version
|
||||||
|
unsigned long long int hex1 = ((unsigned long long int)v0 << 40ULL) + ((unsigned long long int)v1 << 17ULL) + ((unsigned long long int)v2 << 6ULL) + (v3 >> 8);
|
||||||
|
unsigned long long int hex2 = v3 & 0xFF;
|
||||||
|
|
||||||
|
//49 bit version prior to golay correction and c1 demodulation pN
|
||||||
|
unsigned long long int hex49 = ((unsigned long long int)c0 << 37ULL) + ((unsigned long long int)c1 << 25ULL) + ((unsigned long long int)v2 << 14ULL) + v3;
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
|
||||||
|
if (opts->payload == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AMBE HEX(72): %016llX%02llX \n", hex1, hex2);
|
||||||
|
fprintf (stderr, " AMBE HEX(49): %014llX\n", hex49 << 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//de-interleaved code words for AMBE+2
|
||||||
|
void ambe2_codeword_print_f (dsd_opts * opts, char ambe_fr[4][24])
|
||||||
|
{
|
||||||
|
uint32_t v0 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[0], 24); //24
|
||||||
|
uint32_t v1 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[1], 23); //23
|
||||||
|
uint32_t v2 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[2], 11); //11
|
||||||
|
uint32_t v3 = (uint32_t)convert_bits_into_output((uint8_t *)ambe_fr[3], 14); //14
|
||||||
|
|
||||||
|
// if (opts->payload == 1)
|
||||||
|
// fprintf (stderr, " AMBE V0: %06X; V1: %06X; V2: %03X; V3: %04X; \n", v0, v1, v2, v3);
|
||||||
|
|
||||||
|
unsigned long long int hex1 = ((unsigned long long int)v0 << 40ULL) + ((unsigned long long int)v1 << 17ULL) + ((unsigned long long int)v2 << 6ULL) + (v3 >> 8);
|
||||||
|
unsigned long long int hex2 = v3 & 0xFF;
|
||||||
|
|
||||||
|
if (opts->payload == 1)
|
||||||
|
fprintf (stderr, " AMBE HEX(72): %016llX%02llX \n", hex1, hex2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: This mode DOES NOT work over a repeater, simplex only
|
||||||
|
//repeaters may or will attempt to correct the frame errors
|
||||||
|
void tyt16_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24], int fnum)
|
||||||
|
{
|
||||||
|
|
||||||
|
char interleaved[72];
|
||||||
|
memset (interleaved, 0, sizeof(interleaved));
|
||||||
|
|
||||||
|
//interleave the frame
|
||||||
|
const int *w, *x, *y, *z;
|
||||||
|
w = rW; x = rX; y = rY; z = rZ;
|
||||||
|
|
||||||
|
for (int8_t i = 0; i < 36; i++)
|
||||||
|
{
|
||||||
|
interleaved[(i*2)+0] = ambe_fr[*w][*x];
|
||||||
|
interleaved[(i*2)+1] = ambe_fr[*y][*z];
|
||||||
|
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ks_bytes[10]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
uint8_t ks[80]; memset(ks, 0, sizeof(ks));
|
||||||
|
|
||||||
|
ks_bytes[0] = (state->H >> 8) & 0xFF;
|
||||||
|
ks_bytes[1] = (state->H >> 0) & 0xFF;
|
||||||
|
|
||||||
|
//copy same bytes into rest of byte array
|
||||||
|
for (int16_t i = 2; i < 10; i++)
|
||||||
|
ks_bytes[i] = ks_bytes[i%2];
|
||||||
|
|
||||||
|
//convert byte array into a bit array
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks, 10);
|
||||||
|
|
||||||
|
//set ks idx position (-1)
|
||||||
|
int idx = 0;
|
||||||
|
if (fnum == 0)
|
||||||
|
idx = 79;
|
||||||
|
else idx = 71;
|
||||||
|
|
||||||
|
//apply keystream to interleave
|
||||||
|
for (int8_t i = 0; i < 72; i++)
|
||||||
|
interleaved[i] ^= ks[idx--];
|
||||||
|
|
||||||
|
//deinterleave back into ambe_fr frame
|
||||||
|
w = rW; x = rX; y = rY; z = rZ;
|
||||||
|
int k = 0;
|
||||||
|
for (int8_t i = 0; i < 36; i++)
|
||||||
|
{
|
||||||
|
ambe_fr[*w][*x] = interleaved[k++];
|
||||||
|
ambe_fr[*y][*z] = interleaved[k++];
|
||||||
|
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void tyt_ap_pc4_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
unsigned char key1[64]; memset(key1, 0, sizeof(key1));
|
||||||
|
unsigned char key2[64]; memset(key2, 0, sizeof(key2));
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
strncpy(buf, input, sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
|
||||||
|
char *pEnd;
|
||||||
|
uint64_t K1 = strtoull(buf, &pEnd, 16);
|
||||||
|
uint64_t K2 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
uint64_t K3 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
uint64_t K4 = strtoull(pEnd, &pEnd, 16);
|
||||||
|
|
||||||
|
if (K3 != 0 || K4 != 0) //256-bit keys loaded as ASCII characters
|
||||||
|
{
|
||||||
|
//start loading K1, K2, K3, and K4 as ASCII to fill 64 bytes of key1
|
||||||
|
int k = 0; uint8_t x = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K1 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K2 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K3 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
x = ((K4 >> (60-(i*4))) & 0xF);
|
||||||
|
if (x >= 0 && x <= 9) //numbers 0-9
|
||||||
|
x += 0x30; //ASCII representation of numbers is 0x30, 0x31....0x39
|
||||||
|
else x += 0x37; //Upper ASCII A,B,C,D,E,F is 0x41, 0x42...0x46
|
||||||
|
key1[k++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "ASCII: ");
|
||||||
|
// for (int i = 0; i < 64; i++)
|
||||||
|
// fprintf (stderr, " %02X", key1[i]);
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
/* Create key schedule */
|
||||||
|
create_keys(&ctx, key1, 64);
|
||||||
|
ctx.rounds = nbround;
|
||||||
|
|
||||||
|
fprintf(stderr, "DMR TYT AP (PC4) 256-bit Key %016llX%016llX%016llX%016llX with Forced Application\n",
|
||||||
|
(unsigned long long)K1, (unsigned long long)K2, (unsigned long long)K3, (unsigned long long)K4);
|
||||||
|
|
||||||
|
state->tyt_ap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else //128-bit loaded as reverse bytes
|
||||||
|
{
|
||||||
|
|
||||||
|
u64_to_bytes_be(K1, &key1[0]);
|
||||||
|
u64_to_bytes_be(K2, &key1[8]);
|
||||||
|
|
||||||
|
// reverse load the key bytes into key2
|
||||||
|
for (int i=0;i<16;i++)
|
||||||
|
key2[i] = key1[15-i];
|
||||||
|
|
||||||
|
/* Create key schedule */
|
||||||
|
create_keys(&ctx, key2, 16);
|
||||||
|
ctx.rounds = nbround;
|
||||||
|
|
||||||
|
fprintf (stderr,"DMR TYT AP (PC4) 128-bit Key %016llX%016llX with Forced Application\n",
|
||||||
|
(unsigned long long int)K1, (unsigned long long int)K2);
|
||||||
|
|
||||||
|
state->tyt_ap = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void tyt_ep_aes_keystream_creation(dsd_state * state, char * input)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
strncpy(buf, input, 1023);
|
||||||
|
buf[1023] = '\0';
|
||||||
|
|
||||||
|
char *pEnd;
|
||||||
|
unsigned long long int K1 = strtoull (buf, &pEnd, 16);
|
||||||
|
unsigned long long int K2 = strtoull (pEnd, &pEnd, 16);
|
||||||
|
|
||||||
|
//
|
||||||
|
uint8_t static_key[32];
|
||||||
|
memset(static_key, 0, sizeof(static_key));
|
||||||
|
|
||||||
|
//static key value
|
||||||
|
static_key[0]=0x6e; static_key[1]=0x02; static_key[2]=0x8d; static_key[3]=0x8a;
|
||||||
|
static_key[4]=0xca; static_key[5]=0xeb; static_key[6]=0x9b; static_key[7]=0xbe;
|
||||||
|
static_key[8]=0x42; static_key[9]=0x72; static_key[10]=0xfb; static_key[11]=0x82;
|
||||||
|
static_key[12]=0x64; static_key[13]=0x56; static_key[14]=0x31; static_key[15]=0xfa;
|
||||||
|
|
||||||
|
//the key value provided by user
|
||||||
|
uint8_t user_key[16];
|
||||||
|
memset(user_key, 0, sizeof(user_key));
|
||||||
|
|
||||||
|
//Load user key into array to manipulate
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
user_key[i+0] = (K1 >> (56-(i*8))) & 0xFF;
|
||||||
|
user_key[i+8] = (K2 >> (56-(i*8))) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t input_register[16];
|
||||||
|
memset(input_register, 0, sizeof(input_register));
|
||||||
|
|
||||||
|
//manipulate user provided key by loading bytes in reverse order into the input_register
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
input_register[15-i] = user_key[i];
|
||||||
|
|
||||||
|
uint8_t ks_bytes[16];
|
||||||
|
memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
|
||||||
|
//create keystream
|
||||||
|
aes_ofb_keystream_output(input_register, static_key, ks_bytes, 0, 1);
|
||||||
|
uint8_t ks_bits[128];
|
||||||
|
memset(ks_bits, 0, sizeof(ks_bits));
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks_bits, 16);
|
||||||
|
|
||||||
|
//load static keystream into ctx.bits since that isn't ever zeroed out
|
||||||
|
for (int i = 0; i < 49; i++)
|
||||||
|
ctx.bits[i] = ks_bits[i];
|
||||||
|
|
||||||
|
fprintf (stderr,"DMR TYT EP (AES-128) Key %016llX%016llX with Forced Application\n", K1, K2);
|
||||||
|
state->tyt_ep = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect systems 72-bit (9-byte) Extended Encryption //TODO: Move this later
|
||||||
|
void csi72_ambe2_codeword_keystream(dsd_state * state, char ambe_fr[4][24])
|
||||||
|
{
|
||||||
|
|
||||||
|
char interleaved[72];
|
||||||
|
memset (interleaved, 0, sizeof(interleaved));
|
||||||
|
|
||||||
|
//interleave the frame
|
||||||
|
const int *w, *x, *y, *z;
|
||||||
|
w = rW; x = rX; y = rY; z = rZ;
|
||||||
|
|
||||||
|
for (int8_t i = 0; i < 36; i++)
|
||||||
|
{
|
||||||
|
interleaved[(i*2)+0] = ambe_fr[*w][*x];
|
||||||
|
interleaved[(i*2)+1] = ambe_fr[*y][*z];
|
||||||
|
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ks_bytes[9]; memset(ks_bytes, 0, sizeof(ks_bytes));
|
||||||
|
uint8_t ks[72]; memset(ks, 0, sizeof(ks));
|
||||||
|
|
||||||
|
//keys are loaded in reverse byte order, stored in state->static_ks_bits[0]
|
||||||
|
for (int i = 0; i < 9; i++)
|
||||||
|
ks_bytes[i] = state->static_ks_bits[0][8-i];
|
||||||
|
|
||||||
|
//convert byte array into a bit array
|
||||||
|
unpack_byte_array_into_bit_array(ks_bytes, ks, 9);
|
||||||
|
|
||||||
|
//apply keystream to interleave
|
||||||
|
for (int8_t i = 0; i < 72; i++)
|
||||||
|
interleaved[i] ^= ks[71-i];
|
||||||
|
|
||||||
|
//deinterleave back into ambe_fr frame
|
||||||
|
w = rW; x = rX; y = rY; z = rZ;
|
||||||
|
int k = 0;
|
||||||
|
for (int8_t i = 0; i < 36; i++)
|
||||||
|
{
|
||||||
|
ambe_fr[*w][*x] = interleaved[k++];
|
||||||
|
ambe_fr[*y][*z] = interleaved[k++];
|
||||||
|
|
||||||
|
w++;
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
830
src/dmr_block.c
830
src/dmr_block.c
File diff suppressed because it is too large
Load Diff
378
src/dmr_bs.c
378
src/dmr_bs.c
@@ -9,12 +9,15 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include "dmr_const.h"
|
#include "dmr_const.h"
|
||||||
|
|
||||||
|
// #define PRINT_AMBE72 //enable to view 72-bit AMBE codewords
|
||||||
|
|
||||||
//A subroutine for processing each TDMA frame individually to allow for
|
//A subroutine for processing each TDMA frame individually to allow for
|
||||||
//processing voice and/or data on both BS slots (channels) simultaneously
|
//processing voice and/or data on both BS slots (channels) simultaneously
|
||||||
void dmrBS (dsd_opts * opts, dsd_state * state)
|
void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
int i, dibit;
|
char * timestr = NULL;
|
||||||
|
|
||||||
|
int i, dibit;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
char ambe_fr2[4][24];
|
char ambe_fr2[4][24];
|
||||||
char ambe_fr3[4][24];
|
char ambe_fr3[4][24];
|
||||||
@@ -30,8 +33,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
char sync[25];
|
char sync[25];
|
||||||
char syncdata[48];
|
uint8_t syncdata[48];
|
||||||
unsigned char EmbeddedSignalling[16];
|
memset (syncdata, 0, sizeof(syncdata));
|
||||||
|
|
||||||
|
uint8_t emb_pdu[16];
|
||||||
|
memset (emb_pdu, 0, sizeof(emb_pdu));
|
||||||
|
|
||||||
uint8_t emb_ok = 0;
|
uint8_t emb_ok = 0;
|
||||||
uint8_t tact_okay = 0;
|
uint8_t tact_okay = 0;
|
||||||
@@ -52,22 +58,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t dummy_bits[196];
|
uint8_t dummy_bits[196];
|
||||||
memset (dummy_bits, 0, sizeof(dummy_bits));
|
memset (dummy_bits, 0, sizeof(dummy_bits));
|
||||||
|
|
||||||
//add time to mirror printFrameSync
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Init slot lights
|
//Init slot lights
|
||||||
sprintf (state->slot1light, " slot1 ");
|
sprintf (state->slot1light, " slot1 ");
|
||||||
sprintf (state->slot2light, " slot2 ");
|
sprintf (state->slot2light, " slot2 ");
|
||||||
@@ -75,8 +65,18 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
//Init the color code status
|
//Init the color code status
|
||||||
state->color_code_ok = 0;
|
state->color_code_ok = 0;
|
||||||
|
|
||||||
vc1 = 2;
|
//if coming from the bootsrap, then the slot will still be assigned the last value
|
||||||
vc2 = 2;
|
//we want to set only that vc value to 2, the other to 7
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
vc1 = 2;
|
||||||
|
vc2 = 7;
|
||||||
|
}
|
||||||
|
if (state->currentslot == 1)
|
||||||
|
{
|
||||||
|
vc1 = 7;
|
||||||
|
vc2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
short int loop = 1;
|
short int loop = 1;
|
||||||
short int skipcount = 0;
|
short int skipcount = 0;
|
||||||
@@ -101,9 +101,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
cleanupAndExit (opts, state);
|
cleanupAndExit (opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timestr = getTimeC();
|
||||||
|
|
||||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||||
|
memset (emb_pdu, 0, sizeof(emb_pdu));
|
||||||
|
memset (syncdata, 0, sizeof(syncdata));
|
||||||
|
|
||||||
internalslot = -1; //reset here so we know if this value is being set properly
|
internalslot = -1; //reset here so we know if this value is being set properly
|
||||||
for(i = 0; i < 12; i++)
|
for(i = 0; i < 12; i++)
|
||||||
@@ -192,19 +196,19 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
dibit = getDibit(opts, state);
|
dibit = getDibit(opts, state);
|
||||||
state->dmr_stereo_payload[i+66] = dibit;
|
state->dmr_stereo_payload[i+66] = dibit;
|
||||||
sync[i] = (dibit | 1) + 48; //how does this work again?
|
sync[i] = (dibit | 1) + 48; //Sync Burst String as ones and threes
|
||||||
|
|
||||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||||
|
|
||||||
//embedded link control
|
//embedded link control
|
||||||
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E
|
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D E, and F
|
||||||
{
|
{
|
||||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0
|
state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D and E
|
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D E, and F
|
||||||
{
|
{
|
||||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0
|
state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0
|
||||||
@@ -213,8 +217,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
sync[24] = 0;
|
sync[24] = 0;
|
||||||
|
|
||||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
for(i = 0; i < 8; i++) emb_pdu[i + 0] = syncdata[i];
|
||||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||||
|
|
||||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||||
for(i = 0; i < 18; i++)
|
for(i = 0; i < 18; i++)
|
||||||
@@ -264,7 +268,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
if (internalslot == 0)
|
if (internalslot == 0)
|
||||||
{
|
{
|
||||||
if (opts->inverted_dmr == 0)
|
if (opts->inverted_dmr == 0)
|
||||||
@@ -273,7 +277,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else fprintf (stderr,"Sync: -DMR ");
|
else fprintf (stderr,"Sync: -DMR ");
|
||||||
|
|
||||||
vc1 = 1;
|
vc1 = 7; //set to 7 so we can see that we should not be on a VC unless a framesync comes in for it first
|
||||||
|
|
||||||
//close MBEout file - slot 1
|
//close MBEout file - slot 1
|
||||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||||
@@ -286,7 +290,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
else fprintf (stderr,"Sync: -DMR ");
|
else fprintf (stderr,"Sync: -DMR ");
|
||||||
|
|
||||||
vc2 = 1;
|
vc2 = 7; //set to 7 so we can see that we should not be on a VC unless a framesync comes in for it first
|
||||||
|
|
||||||
//close MBEout file - slot 2
|
//close MBEout file - slot 2
|
||||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||||
@@ -297,26 +301,138 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
goto SKIP;
|
goto SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
//only play voice on no data sync
|
//ETSI TS 102 361-1 V2.6.1 Table E.2 and E.4
|
||||||
|
//check for a rc burst with bptc or 34 rate data in it (testing only)
|
||||||
|
// #define RC_TESTING //disable if not in use
|
||||||
|
#ifdef RC_TESTING
|
||||||
|
|
||||||
|
//skip the vc counter, just look at the QR and P/Pi if not voice or data sync pattern
|
||||||
|
if ( (strcmp (sync, DMR_BS_DATA_SYNC) != 0) && (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) )
|
||||||
|
{
|
||||||
|
|
||||||
|
//Golay_20_8_decode FEC for the burst type (SlotType)
|
||||||
|
unsigned char SlotType[20];
|
||||||
|
memset (SlotType, 0, sizeof(SlotType));
|
||||||
|
uint8_t k = 61;
|
||||||
|
for (uint8_t i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
SlotType[(i*2)+0] = (state->dmr_stereo_payload[k+0] >> 1) & 1;
|
||||||
|
SlotType[(i*2)+1] = (state->dmr_stereo_payload[k++] >> 0) & 1;
|
||||||
|
}
|
||||||
|
k = 90;
|
||||||
|
for (uint8_t i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
SlotType[(i*2)+10] = (state->dmr_stereo_payload[k+0] >> 1) & 1;
|
||||||
|
SlotType[(i*2)+11] = (state->dmr_stereo_payload[k++] >> 0) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the QR FEC is good, tact/cach FEC is good, and slot type burst FEC is good, and the P/PI bit is on for RC
|
||||||
|
//NOTE: This can still trigger on bad signal when it should be a data sync pattern but signal drops out or
|
||||||
|
//occassionally on p_clear with trunking tuner logic active and partial stale dibits in the buffer
|
||||||
|
if (QR_16_7_6_decode(emb_pdu) && emb_pdu[4] && tact_okay == 1) //during voice test
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Golay_20_8_decode(SlotType))
|
||||||
|
{
|
||||||
|
fprintf (stderr,"%s ", timestr);
|
||||||
|
if (opts->inverted_dmr == 0)
|
||||||
|
fprintf (stderr,"Sync: +RC ");
|
||||||
|
else fprintf (stderr,"Sync: -RC ");
|
||||||
|
|
||||||
|
dmr_data_sync (opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 48; i++)
|
||||||
|
state->dmr_embedded_signalling[internalslot][5][i] = syncdata[i];
|
||||||
|
|
||||||
|
dmr_sbrc (opts, state, emb_pdu[4]);
|
||||||
|
|
||||||
|
emb_ok = 1;
|
||||||
|
|
||||||
|
//give an audio cue when this happens (low, high)
|
||||||
|
beeper (opts, state, internalslot, 40, 86, 3);
|
||||||
|
beeper (opts, state, internalslot, 80, 86, 3);
|
||||||
|
|
||||||
|
//put into Event History
|
||||||
|
state->event_history_s[0].Event_History_Items[internalslot].color_pair = 4;
|
||||||
|
watchdog_event_datacall (opts, state, 0, 0, "DMR Reverse Channel P/PI Indicator On (FEC Okay);", internalslot);
|
||||||
|
push_event_history (&state->event_history_s[internalslot]);
|
||||||
|
init_event_history (&state->event_history_s[internalslot], 0, 1);
|
||||||
|
|
||||||
|
if (Golay_20_8_decode(SlotType))
|
||||||
|
{
|
||||||
|
skipcount++;
|
||||||
|
goto SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //RC_TESTING
|
||||||
|
|
||||||
|
//check to see if we are expecting a VC at this point vc > 7
|
||||||
|
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0 && internalslot == 0 && vc1 > 6)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"%s ", timestr);
|
||||||
|
|
||||||
|
//simplifying things
|
||||||
|
// char polarity[3];
|
||||||
|
char light[18];
|
||||||
|
|
||||||
|
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||||
|
fprintf (stderr,"Sync: DMR %s", light);
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, "| Frame Sync Err: %d", vc1);
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
vc1++;
|
||||||
|
//this should give it enough time to find the next frame sync pattern, if it exists, if not, then trigger a resync
|
||||||
|
if ( vc1 > 13 ) goto END;
|
||||||
|
else goto SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check to see if we are expecting a VC at this point vc > 7
|
||||||
|
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0 && internalslot == 1 && vc2 > 6)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"%s ", timestr);
|
||||||
|
|
||||||
|
//simplifying things
|
||||||
|
// char polarity[3];
|
||||||
|
char light[18];
|
||||||
|
|
||||||
|
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||||
|
fprintf (stderr,"Sync: DMR %s", light);
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, "| Frame Sync Err: %d", vc2);
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
vc2++;
|
||||||
|
//this should give it enough time to find the next frame sync pattern, if it exists, if not, then trigger a resync
|
||||||
|
if ( vc2 > 13 ) goto END;
|
||||||
|
else goto SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
//only play voice on no data sync, and VC values are within expected values 1-6
|
||||||
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure
|
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure
|
||||||
{
|
{
|
||||||
|
|
||||||
//check the embedded signalling, if bad at this point, we probably aren't quite in sync
|
//check the embedded signalling, if bad at this point, we probably aren't quite in sync
|
||||||
if(QR_16_7_6_decode(EmbeddedSignalling)) emb_ok = 1;
|
if(QR_16_7_6_decode(emb_pdu)) emb_ok = 1;
|
||||||
else emb_ok = 0;
|
else emb_ok = 0;
|
||||||
|
|
||||||
//disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs
|
//disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs
|
||||||
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
||||||
else if (emb_ok == 1)
|
else if (emb_ok == 1)
|
||||||
{
|
{
|
||||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
cc = ((emb_pdu[0] << 3) + (emb_pdu[1] << 2) + (emb_pdu[2] << 1) + emb_pdu[3]);
|
||||||
power = EmbeddedSignalling[4];
|
power = emb_pdu[4];
|
||||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
lcss = ((emb_pdu[5] << 1) + emb_pdu[6]);
|
||||||
|
state->dmr_color_code = state->color_code = cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
skipcount = 0; //reset skip count if processing voice frames
|
skipcount = 0; //reset skip count if processing voice frames
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
|
|
||||||
//simplifying things
|
//simplifying things
|
||||||
char polarity[3];
|
char polarity[3];
|
||||||
@@ -340,11 +456,15 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||||
else sprintf (polarity, "%s", "-");
|
else sprintf (polarity, "%s", "-");
|
||||||
|
if (state->dmr_color_code != 16)
|
||||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
||||||
|
else fprintf (stderr,"Sync: %sDMR %s| Color Code=XX | VC%d ", polarity, light, vc);
|
||||||
|
|
||||||
if (internalslot == 0 && vc1 == 6)
|
if (internalslot == 0 && vc1 == 6)
|
||||||
{
|
{
|
||||||
|
//this needs to run prior to embedded link control
|
||||||
|
if (state->payload_algid == 0x02)
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
//process embedded link control
|
//process embedded link control
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||||
@@ -355,6 +475,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (internalslot == 1 && vc2 == 6)
|
if (internalslot == 1 && vc2 == 6)
|
||||||
{
|
{
|
||||||
|
//this needs to run prior to embedded link control
|
||||||
|
if (state->payload_algidR == 0x02)
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
//process embedded link control
|
//process embedded link control
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||||
@@ -372,6 +495,26 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
|
if (state->tyt_bp == 1)
|
||||||
|
{
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr, 0);
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr2, 1);
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->csi_ee == 1)
|
||||||
|
{
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PRINT_AMBE72
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr3);
|
||||||
|
#endif
|
||||||
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
if(internalslot == 0)
|
if(internalslot == 0)
|
||||||
{
|
{
|
||||||
@@ -419,31 +562,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
//'DSP' output to file -- run before sbrc
|
||||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
|
||||||
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
|
||||||
|
|
||||||
cach_err = dmr_cach (opts, state, cachdata);
|
|
||||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
// run alg refresh after vc6 ambe processing
|
|
||||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
|
||||||
if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state);
|
|
||||||
|
|
||||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
|
||||||
|
|
||||||
//increment the vc counters
|
|
||||||
if (internalslot == 0) vc1++;
|
|
||||||
if (internalslot == 1) vc2++;
|
|
||||||
|
|
||||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
|
||||||
if (opts->p25_is_tuned == 1)
|
|
||||||
{
|
|
||||||
state->last_vc_sync_time = time(NULL);
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//'DSP' output to file
|
|
||||||
if (opts->use_dsp_output == 1)
|
if (opts->use_dsp_output == 1)
|
||||||
{
|
{
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
@@ -463,6 +582,34 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||||
|
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||||
|
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
||||||
|
|
||||||
|
cach_err = dmr_cach (opts, state, cachdata);
|
||||||
|
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||||
|
|
||||||
|
// run alg refresh after vc6 ambe processing
|
||||||
|
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||||
|
if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state);
|
||||||
|
|
||||||
|
if (internalslot == 0 && vc1 == 6) state->static_ks_counter[0] = 0;
|
||||||
|
if (internalslot == 1 && vc2 == 6) state->static_ks_counter[1] = 0;
|
||||||
|
|
||||||
|
if (opts->dmr_le != 2) //if not Hytera Enhanced
|
||||||
|
dmr_late_entry_mi_fragment (opts, state, vc%7, m1, m2, m3);
|
||||||
|
|
||||||
|
//increment the vc counters
|
||||||
|
if (internalslot == 0) vc1++;
|
||||||
|
if (internalslot == 1) vc2++;
|
||||||
|
|
||||||
|
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||||
|
if (opts->p25_is_tuned == 1)
|
||||||
|
{
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
//reset err checks
|
//reset err checks
|
||||||
cach_err = 1;
|
cach_err = 1;
|
||||||
tact_okay = 0;
|
tact_okay = 0;
|
||||||
@@ -503,6 +650,21 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
ncursesPrinter(opts, state);
|
ncursesPrinter(opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//slot 1
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
|
//slot 2 for TDMA systems
|
||||||
|
watchdog_event_history(opts, state, 1);
|
||||||
|
watchdog_event_current(opts, state, 1);
|
||||||
|
|
||||||
|
//
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
} // while loop
|
} // while loop
|
||||||
|
|
||||||
END:
|
END:
|
||||||
@@ -526,7 +688,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
if (tact_okay != 1 || emb_ok != 1)
|
if (tact_okay != 1 || emb_ok != 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
fprintf (stderr,"Sync: DMR ");
|
fprintf (stderr,"Sync: DMR ");
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
||||||
@@ -538,17 +700,40 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
|||||||
state->currentslot = 0;
|
state->currentslot = 0;
|
||||||
dmr_alg_refresh (opts, state);
|
dmr_alg_refresh (opts, state);
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid == 0x02)
|
||||||
|
{
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
|
state->currentslot = 0;
|
||||||
|
dmr_alg_refresh (opts, state);
|
||||||
|
}
|
||||||
if (state->payload_algidR >= 0x21)
|
if (state->payload_algidR >= 0x21)
|
||||||
{
|
{
|
||||||
state->currentslot = 1;
|
state->currentslot = 1;
|
||||||
dmr_alg_refresh (opts, state);
|
dmr_alg_refresh (opts, state);
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algidR == 0x02)
|
||||||
|
{
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
|
state->currentslot = 1;
|
||||||
|
dmr_alg_refresh (opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
//failsafe to reset all data header and blocks when bad tact or emb
|
//failsafe to reset all data header and blocks when bad tact or emb
|
||||||
dmr_reset_blocks (opts, state);
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset static ks counter
|
||||||
|
state->static_ks_counter[0] = 0;
|
||||||
|
state->static_ks_counter[1] = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
||||||
@@ -585,21 +770,8 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
15, 3, 16, 4, 17, 18,
|
15, 3, 16, 4, 17, 18,
|
||||||
19, 5, 20, 21, 22, 6, 23
|
19, 5, 20, 21, 22, 6, 23
|
||||||
};
|
};
|
||||||
//add time to mirror printFrameSync
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
char * timestr = getTimeC();
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//payload buffer
|
//payload buffer
|
||||||
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
||||||
@@ -632,6 +804,9 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
internalslot = state->currentslot = tact_bits[1];
|
internalslot = state->currentslot = tact_bits[1];
|
||||||
|
|
||||||
|
//reset static ks counter
|
||||||
|
state->static_ks_counter[internalslot] = 0;
|
||||||
|
|
||||||
//Setup for first AMBE Frame
|
//Setup for first AMBE Frame
|
||||||
|
|
||||||
//Interleave Schedule
|
//Interleave Schedule
|
||||||
@@ -748,7 +923,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
char polarity[3];
|
char polarity[3];
|
||||||
char light[18];
|
char light[18];
|
||||||
|
|
||||||
@@ -766,8 +941,9 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||||
else sprintf (polarity, "%s", "-");
|
else sprintf (polarity, "%s", "-");
|
||||||
|
if (state->dmr_color_code != 16)
|
||||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code);
|
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code);
|
||||||
|
else fprintf (stderr,"Sync: %sDMR %s| Color Code=XX | VC1*", polarity, light);
|
||||||
|
|
||||||
dmr_alg_reset (opts, state);
|
dmr_alg_reset (opts, state);
|
||||||
|
|
||||||
@@ -778,6 +954,26 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
|
if (state->tyt_bp == 1)
|
||||||
|
{
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr, 0);
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr2, 1);
|
||||||
|
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->csi_ee == 1)
|
||||||
|
{
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PRINT_AMBE72
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr3);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
@@ -830,7 +1026,8 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//collect the mi fragment
|
//collect the mi fragment
|
||||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
if (opts->dmr_le != 2) //if not Hytera Enhanced
|
||||||
|
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||||
|
|
||||||
cach_err = dmr_cach (opts, state, cachdata);
|
cach_err = dmr_cach (opts, state, cachdata);
|
||||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||||
@@ -849,7 +1046,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
//if we have a tact err, then produce sync pattern/err message
|
//if we have a tact err, then produce sync pattern/err message
|
||||||
if (tact_okay != 1 || sync_okay != 1)
|
if (tact_okay != 1 || sync_okay != 1)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
fprintf (stderr,"Sync: DMR ");
|
fprintf (stderr,"Sync: DMR ");
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
fprintf (stderr, "| VOICE CACH/SYNC ERR");
|
fprintf (stderr, "| VOICE CACH/SYNC ERR");
|
||||||
@@ -861,15 +1058,32 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
state->currentslot = 0;
|
state->currentslot = 0;
|
||||||
dmr_alg_refresh (opts, state);
|
dmr_alg_refresh (opts, state);
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid == 0x02)
|
||||||
|
{
|
||||||
|
state->currentslot = 0;
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
|
dmr_alg_refresh (opts, state);
|
||||||
|
}
|
||||||
if (state->payload_algidR >= 0x21)
|
if (state->payload_algidR >= 0x21)
|
||||||
{
|
{
|
||||||
state->currentslot = 1;
|
state->currentslot = 1;
|
||||||
dmr_alg_refresh (opts, state);
|
dmr_alg_refresh (opts, state);
|
||||||
}
|
}
|
||||||
|
else if (state->payload_algid == 0x02)
|
||||||
|
{
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
|
state->currentslot = 1;
|
||||||
|
dmr_alg_refresh (opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
//failsafe to reset all data header and blocks when bad tact or emb
|
//failsafe to reset all data header and blocks when bad tact or emb
|
||||||
dmr_reset_blocks (opts, state);
|
dmr_reset_blocks (opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
451
src/dmr_csbk.c
451
src/dmr_csbk.c
@@ -3,7 +3,7 @@
|
|||||||
* DMR Control Signal Data PDU (CSBK, MBC) Handler and Related Functions
|
* DMR Control Signal Data PDU (CSBK, MBC) Handler and Related Functions
|
||||||
*
|
*
|
||||||
* Portions of Connect+ code reworked from Boatbod OP25
|
* Portions of Connect+ code reworked from Boatbod OP25
|
||||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
* Source: https://github.com/boatbod/op25/blob/master/op25/gr-op25_repeater/lib/dmr_slot.cc
|
||||||
*
|
*
|
||||||
* Portions of Capacity+ code reworked from Eric Cottrell
|
* Portions of Capacity+ code reworked from Eric Cottrell
|
||||||
* Source: https://github.com/LinuxSheeple-E/dsd/blob/Feature/DMRECC/dmr_csbk.c
|
* Source: https://github.com/LinuxSheeple-E/dsd/blob/Feature/DMRECC/dmr_csbk.c
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
*-----------------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
#define PCLEAR_TUNE_AWAY //disable if slower return is preferred
|
||||||
//function for handling Control Signalling PDUs (CSBK, MBC) messages
|
//function for handling Control Signalling PDUs (CSBK, MBC) messages
|
||||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||||
{
|
{
|
||||||
@@ -283,11 +283,40 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
{
|
{
|
||||||
state->lasttg = target;
|
state->lasttg = target;
|
||||||
state->lastsrc = source;
|
state->lastsrc = source;
|
||||||
|
|
||||||
|
//fix call string for per call, etc
|
||||||
|
sprintf (state->call_string[0], " Trunked "); //catch all
|
||||||
|
if (csbk_o == 49 || csbk_o == 50)
|
||||||
|
sprintf (state->call_string[0], " Group ");
|
||||||
|
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else sprintf (state->call_string[0], " Private ");
|
||||||
|
if (st2)
|
||||||
|
{
|
||||||
|
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else strcat (state->call_string[0], " Emergency ");
|
||||||
|
}
|
||||||
|
else strcat (state->call_string[0], " ");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lcn == 1 && data_call == 0)
|
if (lcn == 1 && data_call == 0)
|
||||||
{
|
{
|
||||||
state->lasttgR = target;
|
state->lasttgR = target;
|
||||||
state->lastsrcR = source;
|
state->lastsrcR = source;
|
||||||
|
|
||||||
|
//fix call string for per call, etc
|
||||||
|
sprintf (state->call_string[1], " Trunked "); //catch all
|
||||||
|
if (csbk_o == 49 || csbk_o == 50)
|
||||||
|
sprintf (state->call_string[1], " Group ");
|
||||||
|
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else sprintf (state->call_string[1], " Private ");
|
||||||
|
if (st2)
|
||||||
|
{
|
||||||
|
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else strcat (state->call_string[1], " Emergency ");
|
||||||
|
}
|
||||||
|
else strcat (state->call_string[1], " ");
|
||||||
|
|
||||||
}
|
}
|
||||||
//Guess I forgot to add this condition here
|
//Guess I forgot to add this condition here
|
||||||
if (GetCurrentFreq(opts->rigctl_sockfd) != freq)
|
if (GetCurrentFreq(opts->rigctl_sockfd) != freq)
|
||||||
@@ -297,6 +326,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
SetFreq(opts->rigctl_sockfd, freq);
|
SetFreq(opts->rigctl_sockfd, freq);
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
|
state->last_t3_tune_time = time(NULL); //set here so a random p_clear on the opposite slot doesn't send us back to the CC
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,11 +341,39 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
{
|
{
|
||||||
state->lasttg = target;
|
state->lasttg = target;
|
||||||
state->lastsrc = source;
|
state->lastsrc = source;
|
||||||
|
|
||||||
|
//fix call string for per call, etc
|
||||||
|
sprintf (state->call_string[0], " Trunked "); //catch all
|
||||||
|
if (csbk_o == 49 || csbk_o == 50)
|
||||||
|
sprintf (state->call_string[0], " Group ");
|
||||||
|
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else sprintf (state->call_string[0], " Private ");
|
||||||
|
if (st2)
|
||||||
|
{
|
||||||
|
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else strcat (state->call_string[0], " Emergency ");
|
||||||
|
}
|
||||||
|
else strcat (state->call_string[0], " ");
|
||||||
|
|
||||||
}
|
}
|
||||||
if (lcn == 1 && data_call == 0)
|
if (lcn == 1 && data_call == 0)
|
||||||
{
|
{
|
||||||
state->lasttgR = target;
|
state->lasttgR = target;
|
||||||
state->lastsrcR = source;
|
state->lastsrcR = source;
|
||||||
|
|
||||||
|
//fix call string for per call, etc
|
||||||
|
sprintf (state->call_string[1], " Trunked "); //catch all
|
||||||
|
if (csbk_o == 49 || csbk_o == 50)
|
||||||
|
sprintf (state->call_string[1], " Group ");
|
||||||
|
else if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else sprintf (state->call_string[1], " Private ");
|
||||||
|
if (st2)
|
||||||
|
{
|
||||||
|
if (csbk_o == 51 || csbk_o == 52 || csbk_o == 54 || csbk_o == 55 || csbk_o == 56) {} //do nothing
|
||||||
|
else strcat (state->call_string[1], " Emergency ");
|
||||||
|
}
|
||||||
|
else strcat (state->call_string[1], " ");
|
||||||
|
|
||||||
}
|
}
|
||||||
//Guess I forgot to add this condition here
|
//Guess I forgot to add this condition here
|
||||||
uint32_t tempf = (uint32_t)freq;
|
uint32_t tempf = (uint32_t)freq;
|
||||||
@@ -324,6 +383,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
rtl_dev_tune (opts, freq);
|
rtl_dev_tune (opts, freq);
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
|
state->last_t3_tune_time = time(NULL); //set here so a random p_clear on the opposite slot doesn't send us back to the CC
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -369,6 +430,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//when on a CC, rotate the symbol out file every hour, if enabled
|
||||||
|
if (opts->p25_is_tuned == 0) //if not currently tuned on Tier 3 system
|
||||||
|
rotate_symbol_out_file(opts, state); //may need a second check to make sure other slot on T3 standard isn't busy as well
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//P_CLEAR
|
//P_CLEAR
|
||||||
@@ -378,89 +443,172 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//NOTE: Do not zero out lasttg/lastsrc in TLC FLCO when using p_clear, otherwise,
|
//NOTE: Do not zero out lasttg/lastsrc in TLC FLCO when using p_clear, otherwise,
|
||||||
//it will affect the conditions below and fail to trigger on tg_hold
|
//it will affect the conditions below and fail to trigger on tg_hold
|
||||||
|
|
||||||
//test misc conditions to trigger a clear and immediately return to CC
|
//test misc conditions to trigger a clear and immediately return to CC, or remain on current VC;
|
||||||
int clear = 0;
|
int clear = 0;
|
||||||
|
int pslot = state->currentslot; //this slot
|
||||||
|
int oslot = (state->currentslot ^ 1) & 1; //opposite slot
|
||||||
|
pslot++; oslot++; //set to 1 and 2 and not 0 and 1
|
||||||
|
|
||||||
//if no voice activity or data call (when enabled) within trunk_hangtime seconds
|
//if the other slot is IDLE or TLC condition -- May consider disabling this one
|
||||||
if ( ((time(NULL) - state->last_vc_sync_time) > opts->trunk_hangtime) && opts->trunk_tune_data_calls == 0) clear = 1;
|
// if (state->currentslot == 0 && (state->dmrburstR == 9 && state->dmrburstR == 7)) clear = 1;
|
||||||
|
// if (state->currentslot == 0 && (state->dmrburstL == 9 && state->dmrburstL == 7)) clear = 1;
|
||||||
|
|
||||||
//if no voice in the opposite slot currently or data call (when enabled) -- might can disable data call condition here
|
//if no voice header, pi header, or voice sync in the opposite slot currently
|
||||||
if (state->currentslot == 0 && state->dmrburstR != 16) clear = 2; //&& opts->trunk_tune_data_calls == 0
|
if (state->currentslot == 0 && (state->dmrburstR != 16 && state->dmrburstR != 0 && state->dmrburstR != 1)) clear = 2;
|
||||||
if (state->currentslot == 1 && state->dmrburstL != 16) clear = 3; //&& opts->trunk_tune_data_calls == 0
|
if (state->currentslot == 1 && (state->dmrburstL != 16 && state->dmrburstL != 0 && state->dmrburstL != 1)) clear = 3;
|
||||||
|
|
||||||
|
//if tuning and decoding data is desired, then do a secondary check here for data headers and blocks in the opposite slot
|
||||||
|
if (opts->trunk_tune_data_calls == 1)
|
||||||
|
{
|
||||||
|
//if no data header or data block sync in the opposite slot currently
|
||||||
|
if (state->currentslot == 0 && (state->dmrburstR == 6 || state->dmrburstR == 7 || state->dmrburstR == 8 || state->dmrburstR == 10)) clear = 21;
|
||||||
|
if (state->currentslot == 1 && (state->dmrburstL == 6 || state->dmrburstL == 7 || state->dmrburstL == 8 || state->dmrburstL == 10)) clear = 22;
|
||||||
|
}
|
||||||
|
|
||||||
//if we have a tg hold in place that matches traffic that was just on this slot (this will override other calls in the opposite slot)
|
//if we have a tg hold in place that matches traffic that was just on this slot (this will override other calls in the opposite slot)
|
||||||
if (state->currentslot == 0 && state->tg_hold == state->lasttg && state->tg_hold != 0) clear = 4;
|
if (state->currentslot == 0 && state->tg_hold == state->lasttg && state->tg_hold != 0) clear = 4;
|
||||||
if (state->currentslot == 1 && state->tg_hold == state->lasttgR && state->tg_hold != 0) clear = 5;
|
if (state->currentslot == 1 && state->tg_hold == state->lasttgR && state->tg_hold != 0) clear = 5;
|
||||||
|
|
||||||
|
//make sure we aren't sent back immediately by an p_clear condition upon first tuning (i.e., random ENC LO, or end of Data Call)
|
||||||
|
//one second default on hangtime should be an optimal time, but let it be user configurable with hangtime option
|
||||||
|
if ( time(NULL)-state->last_t3_tune_time < opts->trunk_hangtime) clear = 0;
|
||||||
|
|
||||||
//initial line break
|
//initial line break
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " Clear (P_CLEAR) %d", clear);
|
fprintf (stderr, " Clear (P_CLEAR) ");
|
||||||
|
#ifdef PCLEAR_TUNE_AWAY
|
||||||
|
|
||||||
//check to see if this is a dummy csbk sent from link control to signal return to tscc
|
if (opts->p25_trunk == 1)
|
||||||
if (clear && csbk_fid == 255) fprintf (stderr, " No Encrypted Call Trunking; Return to CC; ");
|
|
||||||
if (!clear && csbk_fid == 255) fprintf (stderr, " No Encrypted Call Trunking; Other Slot Busy; ");
|
|
||||||
|
|
||||||
if (clear)
|
|
||||||
{
|
{
|
||||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
|
||||||
|
//check the p_clear logic and report status
|
||||||
|
if (clear && csbk_fid == 255) fprintf (stderr, " Slot %d No Encrypted Call Trunking; Slot %d Free; Return to CC; ", pslot, oslot);
|
||||||
|
else if (!clear && csbk_fid == 255) fprintf (stderr, " Slot %d No Encrypted Call Trunking; Slot %d Busy; Remain on VC;", pslot, oslot);
|
||||||
|
else if (clear && csbk_fid == 254) fprintf (stderr, " Cap+ Rest LSN Change: %d; Slot %d Free; Slot %d Free; Go To Rest LSN;", state->dmr_rest_channel, pslot, oslot); //disabled
|
||||||
|
else if (!clear && csbk_fid == 254) fprintf (stderr, " Cap+ Rest LSN Change: %d; Slot %d Free; Slot %d Busy; Remain on LSN;", state->dmr_rest_channel, pslot, oslot); //disabled
|
||||||
|
else if (clear && csbk_fid == 253) fprintf (stderr, " Cap+ Rest LSN Change: %d; No CSBK Channel Activity; Go To Rest LSN;", state->dmr_rest_channel);
|
||||||
|
else if (!clear && csbk_fid == 253) fprintf (stderr, " Cap+ Rest LSN Change: %d; CSBK Channel Activity; Remain on LSN;", state->dmr_rest_channel); //this should never happen in code
|
||||||
|
else if (!clear && csbk_fid == 12) fprintf (stderr, " Con+ Slot %d Termination: Slot %d Busy Voice or Data Call;", pslot, oslot); //Con+ test clears based on the Call Termination CSBK
|
||||||
|
else if (clear && csbk_fid == 12) fprintf (stderr, " Con+ Slot %d Termination: Slot %d Clear or Control CSBK;", pslot, oslot); //Con+ test clears based on the Call Termination CSBK
|
||||||
|
else if (!clear) fprintf (stderr, " Slot %d Clear; Slot %d Busy; Remain on VC;", pslot, oslot);
|
||||||
|
else if (clear == 1) fprintf (stderr, " Slot %d Clear; Slot %d Idle; Return to CC;", pslot, oslot);
|
||||||
|
else if (clear == 2 || clear == 3) fprintf (stderr, " Slot %d Clear; Slot %d Free; Return to CC;", pslot, oslot);
|
||||||
|
else if (clear == 4 || clear == 5) fprintf (stderr, " Slot %d Clear w/ TG Hold %d; Slot %d Activity Override; Return to CC; ", pslot, state->tg_hold, oslot);
|
||||||
|
//NOTE: Below clears are just conditions for reporting, and not clear to tune away, so they are set back to zero
|
||||||
|
else if (clear == 21 || clear == 22)
|
||||||
{
|
{
|
||||||
|
fprintf (stderr, " Slot %d Clear; Slot %d Data; Remain on DC;", pslot, oslot);
|
||||||
//display/le bug fix when p_clear activated
|
clear = 0; //flag as 0 so we won't tune away until data call is completed
|
||||||
// if (state->currentslot == 0)
|
|
||||||
// {
|
|
||||||
// state->payload_mi = 0;
|
|
||||||
// state->payload_algid = 0;
|
|
||||||
// state->payload_keyid = 0;
|
|
||||||
// state->dmr_so = 0;
|
|
||||||
// }
|
|
||||||
// if (state->currentslot == 1)
|
|
||||||
// {
|
|
||||||
// state->payload_miR = 0;
|
|
||||||
// state->payload_algidR = 0;
|
|
||||||
// state->payload_keyidR = 0;
|
|
||||||
// state->dmr_soR = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//rigctl
|
|
||||||
if (opts->use_rigctl == 1)
|
|
||||||
{
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[state->currentslot], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[state->currentslot], "%s", "");
|
|
||||||
state->last_vc_sync_time = 0;
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
//rtl
|
|
||||||
else if (opts->audio_in_type == 3)
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
//Guess I forgot to add this condition here
|
|
||||||
uint32_t tempf = (uint32_t)state->p25_cc_freq;
|
|
||||||
if (opts->rtlsdr_center_freq != tempf)
|
|
||||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
|
||||||
//reset some strings
|
|
||||||
sprintf (state->call_string[state->currentslot], "%s", " "); //21 spaces
|
|
||||||
sprintf (state->active_channel[state->currentslot], "%s", "");
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->last_vc_sync_time = 0;
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
|
||||||
if (opts->rtlsdr_center_freq != tempf)
|
|
||||||
rtl_dev_tune (opts, state->p25_cc_freq);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (clear)
|
||||||
|
{
|
||||||
|
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
//run a watchdog here so we can update this with the most recent info
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 1);
|
||||||
|
|
||||||
|
//display/le/buzzer bug fix when p_clear activated (unsure why this was disabled)
|
||||||
|
//clear only the current slot initially, then clear both if tuning to a different freq
|
||||||
|
if (state->currentslot == 0 && csbk_fid != 253) //don't reset on Cap+ since we aren't testing based on the current TS
|
||||||
|
{
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->dmr_so = 0;
|
||||||
|
}
|
||||||
|
if (state->currentslot == 1 && csbk_fid != 253)
|
||||||
|
{
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->dmr_soR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//rigctl
|
||||||
|
if (opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
//Guess I forgot to add this condition here
|
||||||
|
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
||||||
|
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
||||||
|
|
||||||
|
//clear both if tuning away to another frequency
|
||||||
|
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
||||||
|
{
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->dmr_so = 0;
|
||||||
|
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->dmr_soR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset some strings
|
||||||
|
sprintf (state->call_string[state->currentslot], "%s", " "); //21 spaces
|
||||||
|
sprintf (state->active_channel[state->currentslot], "%s", "");
|
||||||
|
state->last_vc_sync_time = 0;
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
else if (opts->audio_in_type == 3)
|
||||||
|
{
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
//Guess I forgot to add this condition here
|
||||||
|
uint32_t tempf = (uint32_t)state->p25_cc_freq;
|
||||||
|
if (opts->rtlsdr_center_freq != tempf)
|
||||||
|
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
||||||
|
|
||||||
|
//clear both if tuning away to another frequency
|
||||||
|
if (opts->rtlsdr_center_freq != tempf)
|
||||||
|
{
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->dmr_so = 0;
|
||||||
|
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->dmr_soR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset some strings
|
||||||
|
sprintf (state->call_string[state->currentslot], "%s", " "); //21 spaces
|
||||||
|
sprintf (state->active_channel[state->currentslot], "%s", "");
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
state->last_vc_sync_time = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
if (opts->rtlsdr_center_freq != tempf)
|
||||||
|
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //end if trunking is enabled
|
||||||
|
#else
|
||||||
|
UNUSED (clear); UNUSED(pslot); UNUSED(oslot);
|
||||||
|
#endif //end if PCLEAR_TUNE_AWAY is enabled in code
|
||||||
}
|
}
|
||||||
|
|
||||||
//(P_PROTECT)
|
//(P_PROTECT)
|
||||||
@@ -481,7 +629,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
|
|
||||||
if (p_kind == 0) fprintf (stderr, " Disable Target PTT (DIS_PTT)");
|
if (p_kind == 0) fprintf (stderr, " Disable Target PTT (DIS_PTT)");
|
||||||
if (p_kind == 1) fprintf (stderr, " Enable Target PTT (EN_PTT)");
|
if (p_kind == 1) fprintf (stderr, " Enable Target PTT (EN_PTT)");
|
||||||
if (p_kind == 2) fprintf (stderr, " Call (ILLEGALLY_PARKED)");
|
if (p_kind == 2) fprintf (stderr, " Call Hangtime (ILLEGALLY_PARKED)");
|
||||||
if (p_kind == 3) fprintf (stderr, " Enable Target MS PTT (EN_PTT_ONE_MS)");
|
if (p_kind == 3) fprintf (stderr, " Enable Target MS PTT (EN_PTT_ONE_MS)");
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
@@ -490,6 +638,23 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//check the source and/or target for special gateway identifiers
|
//check the source and/or target for special gateway identifiers
|
||||||
dmr_gateway_identifier (source, target);
|
dmr_gateway_identifier (source, target);
|
||||||
|
|
||||||
|
//change this slot burst type to VLC so the revamped p_clear doesn't tune away
|
||||||
|
if (opts->p25_trunk == 1)
|
||||||
|
{
|
||||||
|
if (gi && opts->trunk_tune_group_calls == 1)
|
||||||
|
{
|
||||||
|
if (state->currentslot == 0) state->dmrburstL = 1;
|
||||||
|
else state->dmrburstR = 1;
|
||||||
|
state->gi[state->currentslot] = 0;
|
||||||
|
}
|
||||||
|
if (!gi && opts->trunk_tune_private_calls == 1)
|
||||||
|
{
|
||||||
|
if (state->currentslot == 0) state->dmrburstL = 1;
|
||||||
|
else state->dmrburstR = 1;
|
||||||
|
state->gi[state->currentslot] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csbk_o == 40) //0x28
|
if (csbk_o == 40) //0x28
|
||||||
@@ -553,8 +718,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
uint8_t ann_res = (uint8_t)ConvertBitIntoBytes(&bpbits1[0], 4);
|
uint8_t ann_res = (uint8_t)ConvertBitIntoBytes(&bpbits1[0], 4);
|
||||||
uint8_t cc_ch1 = (uint8_t)ConvertBitIntoBytes(&bpbits1[4], 4);
|
uint8_t cc_ch1 = (uint8_t)ConvertBitIntoBytes(&bpbits1[4], 4);
|
||||||
uint8_t cc_ch2 = (uint8_t)ConvertBitIntoBytes(&bpbits1[8], 4);
|
uint8_t cc_ch2 = (uint8_t)ConvertBitIntoBytes(&bpbits1[8], 4);
|
||||||
uint8_t ch1_flag = bpbits1[13];
|
uint8_t ch1_flag = bpbits1[12];
|
||||||
uint8_t ch2_flag = bpbits1[14];
|
uint8_t ch2_flag = bpbits1[13];
|
||||||
|
|
||||||
uint16_t bcast_ch1 = (uint16_t)ConvertBitIntoBytes(&bpbits2[0], 12);
|
uint16_t bcast_ch1 = (uint16_t)ConvertBitIntoBytes(&bpbits2[0], 12);
|
||||||
uint16_t bcast_ch2 = (uint16_t)ConvertBitIntoBytes(&bpbits2[12], 12);
|
uint16_t bcast_ch2 = (uint16_t)ConvertBitIntoBytes(&bpbits2[12], 12);
|
||||||
@@ -577,8 +742,8 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
uint16_t t_emerg_timer = (uint16_t)ConvertBitIntoBytes(&bpbits1[0], 9);
|
uint16_t t_emerg_timer = (uint16_t)ConvertBitIntoBytes(&bpbits1[0], 9);
|
||||||
uint8_t t_packet_timer = (uint8_t)ConvertBitIntoBytes(&bpbits1[9], 5);
|
uint8_t t_packet_timer = (uint8_t)ConvertBitIntoBytes(&bpbits1[9], 5);
|
||||||
|
|
||||||
uint16_t t_msms_timer = (uint16_t)ConvertBitIntoBytes(&bpbits1[0], 9);
|
uint16_t t_msms_timer = (uint16_t)ConvertBitIntoBytes(&bpbits2[0], 12);
|
||||||
uint16_t t_msline_timer = (uint16_t)ConvertBitIntoBytes(&bpbits1[0], 9);
|
uint16_t t_msline_timer = (uint16_t)ConvertBitIntoBytes(&bpbits2[12], 12);
|
||||||
|
|
||||||
//just doing the raw values here, and not the decoded values, see clause A.1, Tables A.2, A.3, A.4, A.5
|
//just doing the raw values here, and not the decoded values, see clause A.1, Tables A.2, A.3, A.4, A.5
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
@@ -763,10 +928,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
uint8_t nin = (uint8_t)ConvertBitIntoBytes(&bpbits2[16], 8); //see clause 7.2.41
|
uint8_t nin = (uint8_t)ConvertBitIntoBytes(&bpbits2[16], 8); //see clause 7.2.41
|
||||||
|
|
||||||
//the second bit of the CSI, the rest are reserved (wasteful)
|
//the second bit of the CSI, the rest are reserved (wasteful)
|
||||||
uint8_t hibernate_flag = bpbits1[1];
|
uint8_t hibernate_flag = bpbits2[1];
|
||||||
|
|
||||||
//the first bit of the nin, the rest are reserved (yet again)
|
//the first bit of the nin, the rest are reserved (yet again)
|
||||||
uint8_t reg_tg_sub = bpbits2[0]; //if the MS has to send TG during Registration Process (Zzzzzz)
|
uint8_t reg_tg_sub = bpbits2[16]; //if the MS has to send TG during Registration Process (Zzzzzz)
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, " Hibernate Flag: %d; Reg Flag: %d; RES1: %d; RES2: %X; RES3: %X; BPARMS1: %X", hibernate_flag, reg_tg_sub, bpbits1[0], csi & 0x3F, nin & 0x7F, bparms1);
|
fprintf (stderr, " Hibernate Flag: %d; Reg Flag: %d; RES1: %d; RES2: %X; RES3: %X; BPARMS1: %X", hibernate_flag, reg_tg_sub, bpbits1[0], csi & 0x3F, nin & 0x7F, bparms1);
|
||||||
@@ -828,9 +993,17 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
UNUSED(svc_flag);
|
UNUSED(svc_flag);
|
||||||
UNUSED(als_flag);
|
UNUSED(als_flag);
|
||||||
|
|
||||||
|
char ahoy_str[200]; memset(ahoy_str, 0, sizeof(ahoy_str));
|
||||||
|
sprintf (ahoy_str, "AHOY TGT: %d; SRC: %d; ", ahoy_target, ahoy_source);
|
||||||
|
|
||||||
if (ahoy_gi == 0) fprintf (stderr, "Private ");
|
if (ahoy_gi == 0) fprintf (stderr, "Private ");
|
||||||
else fprintf (stderr, "Group ");
|
else fprintf (stderr, "Group ");
|
||||||
|
|
||||||
|
if (ahoy_gi == 0)
|
||||||
|
strcat (ahoy_str, "Private; ");
|
||||||
|
else strcat (ahoy_str, "Group; ");
|
||||||
|
state->gi[state->currentslot] = ahoy_gi ^ 1;
|
||||||
|
|
||||||
//need to put SVC OPT decoding in here, maybe just copy and paste from FLC?
|
//need to put SVC OPT decoding in here, maybe just copy and paste from FLC?
|
||||||
|
|
||||||
fprintf (stderr, "FID: %02X SVC: %02X ", csbk_fid, svc_opt);
|
fprintf (stderr, "FID: %02X SVC: %02X ", csbk_fid, svc_opt);
|
||||||
@@ -850,9 +1023,49 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
|
|
||||||
fprintf (stderr, "Target: %d; Source: %d; ", ahoy_target, ahoy_source);
|
fprintf (stderr, "Target: %d; Source: %d; ", ahoy_target, ahoy_source);
|
||||||
|
|
||||||
|
if (svc_kind == 0 || svc_kind == 1) strcat (ahoy_str, "Voice Call; ");
|
||||||
|
else if (svc_kind == 2 || svc_kind == 3) strcat (ahoy_str, "Packet Data Call; ");
|
||||||
|
else if (svc_kind == 4 || svc_kind == 5) strcat (ahoy_str, "UDT Short Data Call; ");
|
||||||
|
else if (svc_kind == 6) strcat (ahoy_str, "UDT Short Data Polling Service; ");
|
||||||
|
else if (svc_kind == 7) strcat (ahoy_str, "Status Transport Service; ");
|
||||||
|
else if (svc_kind == 8) strcat (ahoy_str, "Call Diversion Service; ");
|
||||||
|
else if (svc_kind == 9) strcat (ahoy_str, "Call Answer Service; ");
|
||||||
|
else if (svc_kind == 10) strcat (ahoy_str, "Full Duplex Voice Call; ");
|
||||||
|
else if (svc_kind == 11) strcat (ahoy_str, "Full Duplex Packet Data Call; ");
|
||||||
|
else if (svc_kind == 12) strcat (ahoy_str, "Reserved; ");
|
||||||
|
else if (svc_kind == 13) strcat (ahoy_str, "Supplimentary Service (Stun/Revive/Kill/Auth); ");
|
||||||
|
else if (svc_kind == 14) strcat (ahoy_str, "Registration/Authentication; ");
|
||||||
|
else if (svc_kind == 15) strcat (ahoy_str, "Cancel Call Service; ");
|
||||||
|
|
||||||
//check the source and/or target for special gateway identifiers
|
//check the source and/or target for special gateway identifiers
|
||||||
dmr_gateway_identifier (ahoy_source, ahoy_target);
|
dmr_gateway_identifier (ahoy_source, ahoy_target);
|
||||||
|
|
||||||
|
//log ahoy as a data call event //re-enable this if you want, but it can clog up the event history
|
||||||
|
// if (state->currentslot == 0)
|
||||||
|
// {
|
||||||
|
// state->lastsrc = ahoy_source;
|
||||||
|
// state->lasttg = ahoy_target;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// state->lastsrcR = ahoy_source;
|
||||||
|
// state->lasttgR = ahoy_target;
|
||||||
|
// }
|
||||||
|
// watchdog_event_datacall (opts, state, ahoy_source, ahoy_target, ahoy_str, state->currentslot);
|
||||||
|
// if (state->currentslot == 0)
|
||||||
|
// {
|
||||||
|
// state->lastsrc = 0;
|
||||||
|
// state->lasttg = 0;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// state->lastsrcR = 0;
|
||||||
|
// state->lasttgR = 0;
|
||||||
|
// }
|
||||||
|
// watchdog_event_history(opts, state, 0);
|
||||||
|
// watchdog_event_current(opts, state, 0);
|
||||||
|
//end ahoy logging
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (csbk_o == 42)
|
if (csbk_o == 42)
|
||||||
@@ -1026,6 +1239,13 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
}
|
}
|
||||||
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
|
else fprintf (stderr, "Source: %d - Target: %d ", source, target);
|
||||||
|
|
||||||
|
//if trunking and data calls allowed, convert preamble burst to a DATA header burst to hold p_clear or con+
|
||||||
|
if (opts->p25_trunk == 1 && opts->trunk_tune_data_calls == 1)
|
||||||
|
{
|
||||||
|
if (state->currentslot == 0) state->dmrburstL = 6;
|
||||||
|
else state->dmrburstR = 6;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//end tier 2 csbks
|
//end tier 2 csbks
|
||||||
|
|
||||||
@@ -1115,6 +1335,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//tg and channel info for trunking purposes
|
//tg and channel info for trunking purposes
|
||||||
uint16_t t_tg[24];
|
uint16_t t_tg[24];
|
||||||
char cap_active[20]; //local string to concantenate to active channel stuff
|
char cap_active[20]; //local string to concantenate to active channel stuff
|
||||||
|
uint8_t empty[24]; //used to evaluate whether or not all channels are idle or not with memcmp after loading
|
||||||
|
|
||||||
//sanity check
|
//sanity check
|
||||||
if (block_num > 6)
|
if (block_num > 6)
|
||||||
@@ -1127,6 +1348,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
memset (t_tg, 0, sizeof(t_tg));
|
memset (t_tg, 0, sizeof(t_tg));
|
||||||
memset (ch, 0, sizeof(ch));
|
memset (ch, 0, sizeof(ch));
|
||||||
memset (pch, 0, sizeof(pch));
|
memset (pch, 0, sizeof(pch));
|
||||||
|
memset (empty, 0, sizeof(empty));
|
||||||
|
|
||||||
//treating FL as a form of LCSS
|
//treating FL as a form of LCSS
|
||||||
if (fl == 2 || fl == 3) //initial or single block (fl2 or fl3)
|
if (fl == 2 || fl == 3) //initial or single block (fl2 or fl3)
|
||||||
@@ -1143,6 +1365,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
state->cap_plus_block_num[ts]++;
|
state->cap_plus_block_num[ts]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//move assignment until later when evaluating for a p_clear condition
|
||||||
if (rest_channel != state->dmr_rest_channel)
|
if (rest_channel != state->dmr_rest_channel)
|
||||||
{
|
{
|
||||||
state->dmr_rest_channel = rest_channel;
|
state->dmr_rest_channel = rest_channel;
|
||||||
@@ -1151,7 +1374,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//assign to cc freq to follow during no sync
|
//assign to cc freq to follow during no sync
|
||||||
if (state->trunk_chan_map[rest_channel] != 0)
|
if (state->trunk_chan_map[rest_channel] != 0)
|
||||||
{
|
{
|
||||||
state->p25_cc_freq = state->trunk_chan_map[rest_channel];
|
// state->p25_cc_freq = state->trunk_chan_map[rest_channel];
|
||||||
//set to always tuned
|
//set to always tuned
|
||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
}
|
}
|
||||||
@@ -1321,15 +1544,15 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(group_tally*8)+(x*16)+56], 16); //don't change this AGAIN!, this is correct!
|
tg = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[ts][(group_tally*8)+(x*16)+56], 16); //don't change this AGAIN!, this is correct!
|
||||||
if (tg != 0) fprintf (stderr, "%5d; ", tg);
|
if (tg != 0) fprintf (stderr, "%5d; ", tg);
|
||||||
else fprintf (stderr, " P||D; ");
|
else fprintf (stderr, " P||D; ");
|
||||||
//flag as available for tuning if data calls enabled
|
//flag as available for tuning if private calls enabled
|
||||||
if (opts->trunk_tune_data_calls == 1) t_tg[i] = tg; //ch[i] = 1;
|
if (opts->trunk_tune_private_calls == 1) t_tg[i] = tg; //ch[i] = 1;
|
||||||
if (tg != 0) x++;
|
if (tg != 0) x++;
|
||||||
|
|
||||||
//add active channel to display string
|
//add active channel to display string
|
||||||
|
|
||||||
//NOTE: Consider only adding this if user toggled or else
|
//NOTE: Consider only adding this if user toggled or else
|
||||||
//lots of short data bursts blink in and out
|
//lots of short data bursts blink in and out
|
||||||
if (1 == 1) //opts->trunk_tune_data_calls
|
if (1 == 1) //opts->trunk_tune_private_calls
|
||||||
{
|
{
|
||||||
sprintf (cap_active, "LSN:%d PC:%d; ", i+1, tg);
|
sprintf (cap_active, "LSN:%d PC:%d; ", i+1, tg);
|
||||||
strcat (state->active_channel[i+1], cap_active);
|
strcat (state->active_channel[i+1], cap_active);
|
||||||
@@ -1360,6 +1583,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//Test allowing a tg hold to pre-empt a call in progress and tune to the hold TG
|
//Test allowing a tg hold to pre-empt a call in progress and tune to the hold TG
|
||||||
if (state->tg_hold != 0) state->last_vc_sync_time = 0;
|
if (state->tg_hold != 0) state->last_vc_sync_time = 0;
|
||||||
|
|
||||||
|
//if no activity in this window
|
||||||
|
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //may use last_cc_sync_time instead
|
||||||
|
rotate_symbol_out_file(opts, state);
|
||||||
|
|
||||||
//TODO: Consider a method to allow moving the frequency to the rest channel
|
//TODO: Consider a method to allow moving the frequency to the rest channel
|
||||||
//when a TG hold is specified but nether slot carries the TG on Hold;
|
//when a TG hold is specified but nether slot carries the TG on Hold;
|
||||||
//CODED: using slow link control for that
|
//CODED: using slow link control for that
|
||||||
@@ -1424,6 +1651,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
j = 11; //break loop
|
j = 11; //break loop
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1459,6 +1687,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
// else fprintf (stderr, "\n DONT RTL LSN/TG to tune to: %d - %d", j+1, t_tg[j]); //debug
|
// else fprintf (stderr, "\n DONT RTL LSN/TG to tune to: %d - %d", j+1, t_tg[j]); //debug
|
||||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||||
opts->p25_is_tuned = 1;
|
opts->p25_is_tuned = 1;
|
||||||
|
state->last_vc_sync_time = time(NULL);
|
||||||
j = 11; //break loop
|
j = 11; //break loop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1487,6 +1716,25 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
|
memset (state->cap_plus_csbk_bits[ts], 0, sizeof(state->cap_plus_csbk_bits[ts]));
|
||||||
state->cap_plus_block_num[ts] = 0;
|
state->cap_plus_block_num[ts] = 0;
|
||||||
|
|
||||||
|
//check here to see if we can go to the current rest lsn, if not already on it
|
||||||
|
int busy = memcmp (empty, t_tg, sizeof(empty));
|
||||||
|
|
||||||
|
//testing (don't keep setting on quick data call LSN flip flops but same frequency for rest channel, other misc conditions)
|
||||||
|
// if (!busy && rest_channel != state->dmr_rest_channel && opts->p25_trunk == 1 && state->p25_cc_freq != state->trunk_chan_map[rest_channel])
|
||||||
|
if (!busy && opts->p25_trunk == 1 && state->p25_cc_freq != state->trunk_chan_map[rest_channel])
|
||||||
|
{
|
||||||
|
//assign now, ideally, this should always trigger a positive p_clear when needed
|
||||||
|
// state->dmr_rest_channel = rest_channel;
|
||||||
|
|
||||||
|
//update frequency
|
||||||
|
if (state->trunk_chan_map[rest_channel] != 0)
|
||||||
|
state->p25_cc_freq = state->trunk_chan_map[rest_channel];
|
||||||
|
|
||||||
|
//Craft a fake CSBK pdu send it to run as a p_clear to go to rest channel if its available (no calls currently)
|
||||||
|
uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 253;
|
||||||
|
dmr_cspdu (opts, state, dbits, dummy, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} //if (fl == 1 || fl == 3)
|
} //if (fl == 1 || fl == 3)
|
||||||
} //opcode == 0x3E
|
} //opcode == 0x3E
|
||||||
|
|
||||||
@@ -1551,14 +1799,20 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
else if (opt == 3)
|
else if (opt == 3)
|
||||||
fprintf (stderr, " Connect Plus Private Voice Channel Grant;");
|
fprintf (stderr, " Connect Plus Private Voice Channel Grant;");
|
||||||
else fprintf (stderr, " Connect Plus Unknown %02X Channel Grant;", opt);
|
else fprintf (stderr, " Connect Plus Unknown %02X Channel Grant;", opt);
|
||||||
fprintf (stderr, " Target: %d; Source: %d; LCN: %d; TS: %d;", grpAddr, srcAddr, lcn, tslot);
|
fprintf (stderr, " Target: %d; Source: %d; LCN: %d; TS: %d;", grpAddr, srcAddr, lcn, tslot+1);
|
||||||
// fprintf (stderr, " OPT: %02X;", opt); //debug
|
// fprintf (stderr, " OPT: %02X;", opt); //debug
|
||||||
state->dmr_mfid = 0x06;
|
state->dmr_mfid = 0x06;
|
||||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||||
|
|
||||||
//add active channel string for display
|
//add active channel string for display
|
||||||
sprintf (state->active_channel[tslot], "Active VCh: %d TG: %d; ", lcn, grpAddr);
|
if (opt == 2)
|
||||||
|
sprintf (state->active_channel[tslot], "Active Group Ch: %d TG: %d; ", lcn, grpAddr);
|
||||||
|
else if (opt == 3)
|
||||||
|
sprintf (state->active_channel[tslot], "Active Private Ch: %d TG: %d; ", lcn, grpAddr);
|
||||||
|
else //generic channel of unknown type
|
||||||
|
sprintf (state->active_channel[tslot], "Active OPT %02X Ch: %d TG: %d; ", opt, lcn, grpAddr);
|
||||||
|
|
||||||
state->last_active_time = time(NULL);
|
state->last_active_time = time(NULL);
|
||||||
|
|
||||||
//Skip tuning group calls if group calls are disabled
|
//Skip tuning group calls if group calls are disabled
|
||||||
@@ -1668,7 +1922,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
uint8_t tslot = ( (cs_pdu[5] & 0x08 ) >> 3 ) & 1;
|
uint8_t tslot = ( (cs_pdu[5] & 0x08 ) >> 3 ) & 1;
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Connect Plus Data Channel Grant;");
|
fprintf (stderr, " Connect Plus Data Channel Grant;");
|
||||||
fprintf (stderr, " Target: %d; LCN: %d; TS: %d;", dtarget, lcn, tslot);
|
fprintf (stderr, " Target: %d; LCN: %d; TS: %d;", dtarget, lcn, tslot+1);
|
||||||
state->dmr_mfid = 0x06;
|
state->dmr_mfid = 0x06;
|
||||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||||
@@ -1677,7 +1931,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
if (opts->trunk_tune_data_calls == 0) goto SKIPCOND;
|
if (opts->trunk_tune_data_calls == 0) goto SKIPCOND;
|
||||||
|
|
||||||
//add active channel string for display
|
//add active channel string for display
|
||||||
sprintf (state->active_channel[tslot], "Active DCh: %d TG: %d; ", lcn, dtarget);
|
sprintf (state->active_channel[tslot], "Active Data Ch: %d TG: %d; ", lcn, dtarget);
|
||||||
state->last_active_time = time(NULL);
|
state->last_active_time = time(NULL);
|
||||||
|
|
||||||
//NOTE: Only set CC Frequency from SLC since it will tell us
|
//NOTE: Only set CC Frequency from SLC since it will tell us
|
||||||
@@ -1759,25 +2013,21 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Con+ Channel or Call Termination
|
//Con+ Slot Termination
|
||||||
if (csbk_o == 0x0C)
|
if (csbk_o == 0x0C)
|
||||||
{
|
{
|
||||||
//could just be a data call terminator (like TD_LC)
|
|
||||||
//only observed this after a data header or response ack packet
|
|
||||||
//so, its only for data? or the data header and response is a call termination signal?
|
|
||||||
//to be studied some more, will test using the p_clear logic to see
|
|
||||||
//if trunking is faster, or if it breaks
|
|
||||||
|
|
||||||
//initial line break
|
//initial line break
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
uint32_t ttarget = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
uint32_t ttarget = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
// fprintf (stderr, " Connect Plus Channel Termination;");
|
fprintf (stderr, " Connect Plus Slot Termination;");
|
||||||
fprintf (stderr, " Connect Plus Data Call Termination;");
|
|
||||||
fprintf (stderr, " Target: %d;", ttarget);
|
fprintf (stderr, " Target: %d;", ttarget);
|
||||||
//NOTE: Octet 6 seems to have a value (0x0B), but the rest are all zeroes, doesn't line up with an LCN or TS value
|
|
||||||
//test other Con+ systems, see if those have any values in those octets to figure out, also saw
|
//Run p_clear to decide whether or not to return to the control channel
|
||||||
//another octet 9? with an 01 in it a few times, could have been a timeslot bit
|
uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 12;
|
||||||
|
dmr_cspdu (opts, state, dbits, dummy, 1, 0);
|
||||||
|
|
||||||
state->dmr_mfid = 0x06;
|
state->dmr_mfid = 0x06;
|
||||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||||
@@ -1921,6 +2171,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
|||||||
//Test allowing a tg hold to pre-empt a call in progress and tune to the hold TG
|
//Test allowing a tg hold to pre-empt a call in progress and tune to the hold TG
|
||||||
if (state->tg_hold != 0) state->last_vc_sync_time = 0;
|
if (state->tg_hold != 0) state->last_vc_sync_time = 0;
|
||||||
|
|
||||||
|
//if no activity in this window
|
||||||
|
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //may use last_cc_sync_time instead
|
||||||
|
rotate_symbol_out_file(opts, state);
|
||||||
|
|
||||||
//TODO: Consider a method to allow moving the frequency to the free repeater channel
|
//TODO: Consider a method to allow moving the frequency to the free repeater channel
|
||||||
//when a TG hold is specified but nether slot carries the TG on Hold;
|
//when a TG hold is specified but nether slot carries the TG on Hold;
|
||||||
//CODED: using Free repeater in SLC to change over if required
|
//CODED: using Free repeater in SLC to change over if required
|
||||||
@@ -2191,6 +2445,9 @@ void dmr_decode_syscode(dsd_opts * opts, dsd_state * state, uint8_t * cs_pdu_bit
|
|||||||
//raw syscode
|
//raw syscode
|
||||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 14);
|
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 14);
|
||||||
|
|
||||||
|
if (type == 0)
|
||||||
|
state->dmr_t3_syscode = syscode;
|
||||||
|
|
||||||
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
|
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
|
||||||
uint16_t net = 0;
|
uint16_t net = 0;
|
||||||
uint16_t site = 0;
|
uint16_t site = 0;
|
||||||
|
|||||||
@@ -293,8 +293,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|||||||
info[(2*i) + 99] = (1 & dibit); // bit 0
|
info[(2*i) + 99] = (1 & dibit); // bit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't run on MS Reverse Channel Data
|
//
|
||||||
if (state->dmr_ms_rc == 0) dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
||||||
|
|
||||||
//don't run cach on simplex or mono
|
//don't run cach on simplex or mono
|
||||||
if (state->dmr_ms_mode == 0 && opts->dmr_mono == 0)
|
if (state->dmr_ms_mode == 0 && opts->dmr_mono == 0)
|
||||||
@@ -321,40 +321,25 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
|||||||
skipDibit (opts, state, 12 + 49 + 5);
|
skipDibit (opts, state, 12 + 49 + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if using con+ trunking and last voice observed more than x seconds ago, snap back to con+ cc
|
#define CON_TUNEAWAY //disable if any unlock issues noted on the logic
|
||||||
//con+ voice channels can have extremely long idle periods without properly tearing down
|
|
||||||
|
#ifdef CON_TUNEAWAY
|
||||||
|
//simplified, if IDLE condition, drop cc and vc sync time so when RF channel tears down, we go back much quicker
|
||||||
|
//NOTE: This was adopted, because going back to the CC early and then to be sent back to the channel grant,
|
||||||
|
//only for it to tear down and being sent back to the CC again isn't very efficient for trunk tracking
|
||||||
|
//NOTE: This will still leave the tuner in the 'locked' state when tuning a voice channel grant on the CC,
|
||||||
|
//and will remain locked until a new voice channel grant is received, but its just asthetic, trying to fix it
|
||||||
|
//is too much of a hassle and causes other issues like CC hunting, etc.
|
||||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->is_con_plus == 1)
|
||||||
{
|
{
|
||||||
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
int clear = 0;
|
||||||
time_t waitsec = 2;
|
//IF both slots currently signalling IDLE
|
||||||
if (opts->trunk_tune_data_calls == 1)
|
if (state->dmrburstL == 9 && state->dmrburstR == 9) clear = 1;
|
||||||
waitsec = 4; //increase time for a data call before hopping
|
if (clear == 1)
|
||||||
if ( (time(NULL) - state->last_vc_sync_time > waitsec) )
|
|
||||||
{
|
{
|
||||||
if (opts->use_rigctl == 1) //rigctl tuning
|
state->last_cc_sync_time = 0;
|
||||||
{
|
state->last_vc_sync_time = 0;
|
||||||
if (opts->setmod_bw != 0) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
|
||||||
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
|
||||||
//debug
|
|
||||||
fprintf (stderr, " Con+ Timeout; Return to CC;");
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (opts->audio_in_type == 3) //rtl_fm tuning
|
|
||||||
{
|
|
||||||
#ifdef USE_RTLSDR
|
|
||||||
rtl_dev_tune(opts, state->p25_cc_freq);
|
|
||||||
//debug
|
|
||||||
fprintf (stderr, " Con+ Timeout; Return to CC;");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
opts->p25_is_tuned = 0;
|
|
||||||
//zero out vc frequencies
|
|
||||||
state->p25_vc_freq[0] = 0;
|
|
||||||
state->p25_vc_freq[1] = 0;
|
|
||||||
memset (state->active_channel, 0, sizeof(state->active_channel));
|
|
||||||
state->last_cc_sync_time = time(NULL);
|
|
||||||
state->is_con_plus = 0; //con+ flag off
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,6 @@
|
|||||||
|
|
||||||
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
|
||||||
//TODO: Test UDT NMEA and LIP Decoders with Real World Samples (if/when available)
|
//TODO: Test UDT NMEA and LIP Decoders with Real World Samples (if/when available)
|
||||||
//WIP: Move all extra decoders for location, etc, to a new file and add prototypes to dsd.h
|
|
||||||
//TODO: Test CRC9/CRC32 on Rate 1 Data with Real World Samples (if/when available)
|
|
||||||
//TODO: Address areas that require reading of ISO7, ISO8, and UTF-16 string formats
|
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
@@ -143,7 +140,9 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
if (state->data_header_format[slot] == 0) //UDT 1/2 Encoded Blocks
|
if (state->data_header_format[slot] == 0) //UDT 1/2 Encoded Blocks
|
||||||
{
|
{
|
||||||
is_udt = 1;
|
is_udt = 1;
|
||||||
sprintf(state->fsubtype, " UDTC ");
|
if (state->data_conf_data[slot] == 1)
|
||||||
|
sprintf(state->fsubtype, " UDTC "); //confirmed data
|
||||||
|
else sprintf(state->fsubtype, " UDTU "); //unconfirmed data
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x08: //3/4 Rate Data
|
case 0x08: //3/4 Rate Data
|
||||||
@@ -167,11 +166,11 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
crclen = 9; //confirmed data only
|
crclen = 9; //confirmed data only
|
||||||
crcmask = 0x10F;
|
crcmask = 0x10F;
|
||||||
is_full = 1;
|
is_full = 1;
|
||||||
pdu_len = 25; //196 bits - 24.5 bytes
|
pdu_len = 24; //192 bits 24 bytes + 4 pad bits
|
||||||
sprintf(state->fsubtype, " R_1U ");
|
sprintf(state->fsubtype, " R_1U ");
|
||||||
if (state->data_conf_data[slot] == 1)
|
if (state->data_conf_data[slot] == 1)
|
||||||
{
|
{
|
||||||
pdu_len = 23;
|
pdu_len = 22; //start at plus two when assembling
|
||||||
pdu_start = 2; //start at plus two when assembling
|
pdu_start = 2; //start at plus two when assembling
|
||||||
sprintf(state->fsubtype, " R_1C ");
|
sprintf(state->fsubtype, " R_1C ");
|
||||||
}
|
}
|
||||||
@@ -207,7 +206,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
if (databurst != 0xEB)
|
if (databurst != 0xEB)
|
||||||
{
|
{
|
||||||
if (state->dmr_ms_mode == 0) fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code);
|
if (state->dmr_ms_mode == 0)
|
||||||
|
{
|
||||||
|
if (state->dmr_color_code != 16)
|
||||||
|
fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code);
|
||||||
|
else fprintf(stderr, "| Color Code=XX ");
|
||||||
|
}
|
||||||
fprintf(stderr, "|%s", state->fsubtype);
|
fprintf(stderr, "|%s", state->fsubtype);
|
||||||
|
|
||||||
//'DSP' output to file
|
//'DSP' output to file
|
||||||
@@ -499,16 +503,20 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
|
|
||||||
if (is_full) //Rate 1 Data
|
if (is_full) //Rate 1 Data
|
||||||
{
|
{
|
||||||
|
//assembly (w/ confirmed data) on a working Tier III Tait System
|
||||||
|
|
||||||
CRCExtracted = 0;
|
CRCExtracted = 0;
|
||||||
CRCComputed = 0;
|
CRCComputed = 0;
|
||||||
IrrecoverableErrors = 0; //implicit, since there is no encoding
|
IrrecoverableErrors = 0; //implicit, since there is no encoding
|
||||||
|
|
||||||
for (i = 0; i < 12; i++)
|
//pack rate 1 data for a total of up to 24 bytes, (22 if Confirmed Data)
|
||||||
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8);
|
//skipping the 4 padding bits located at 96,97,98,99 using the ptr values
|
||||||
|
//as offsets for confirmed data, len, and continue points for packing
|
||||||
//Skip Padding Bits (96,97,98,99)
|
int bit_ptr = pdu_start * 8;
|
||||||
for (i = 0; i < 12; i++)
|
int byte_ptr = 0;
|
||||||
DMR_PDU[i+12] = (uint8_t)ConvertBitIntoBytes(&info[(i*8)+100], 8);
|
pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12-pdu_start);
|
||||||
|
bit_ptr = 100; byte_ptr = 12-pdu_start;
|
||||||
|
pack_bit_array_into_byte_array (info+bit_ptr, DMR_PDU+byte_ptr, 12);
|
||||||
|
|
||||||
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
|
||||||
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
|
||||||
@@ -522,11 +530,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
CRCExtracted = CRCExtracted ^ crcmask;
|
CRCExtracted = CRCExtracted ^ crcmask;
|
||||||
|
|
||||||
//reorganize the info bit array into confdatabits, just for CRC9 check
|
//reorganize the info bit array into confdatabits, just for CRC9 check
|
||||||
//unconfirmed, haven't seen any samples with rate 1 data
|
int k = 0;
|
||||||
for(i = 0; i < 176; i++) confdatabits[i] = info[i + 16];
|
for (i = 16; i < 96; i++) confdatabits[k++] = info[i]; //first half
|
||||||
for(i = 0; i < 7; i++) confdatabits[i + 176] = info[i];
|
for (i = 100; i < 196; i++) confdatabits[k++] = info[i]; //second half
|
||||||
|
for (i = 0; i < 7; i++) confdatabits[k++] = info[i]; //DBSN
|
||||||
|
CRCComputed = ComputeCrc9Bit(confdatabits, k);
|
||||||
|
|
||||||
CRCComputed = ComputeCrc9Bit(confdatabits, 183);
|
|
||||||
if (CRCExtracted == CRCComputed)
|
if (CRCExtracted == CRCComputed)
|
||||||
{
|
{
|
||||||
CRCCorrect = 1;
|
CRCCorrect = 1;
|
||||||
@@ -534,6 +543,9 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
}
|
}
|
||||||
else state->data_block_crc_valid[slot][blockcounter] = 0;
|
else state->data_block_crc_valid[slot][blockcounter] = 0;
|
||||||
|
|
||||||
|
//debug confirmed data values (working now)
|
||||||
|
// fprintf (stderr, " K: %d; DSBN: %d; CRC: %03X / %03X;", k, dbsn, CRCComputed, CRCExtracted);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy info to dmr_pdu_bits
|
//copy info to dmr_pdu_bits
|
||||||
@@ -546,9 +558,9 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
|||||||
if (databurst == 0x00) dmr_pi (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
if (databurst == 0x00) dmr_pi (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
||||||
|
|
||||||
//full link control
|
//full link control
|
||||||
if (databurst == 0x01) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 1); //VLC
|
if (databurst == 0x01) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, &IrrecoverableErrors, 1); //VLC
|
||||||
if (databurst == 0x02) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 2); //TLC
|
if (databurst == 0x02) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, &IrrecoverableErrors, 2); //TLC
|
||||||
if (databurst == 0xEB) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 3); //EMB
|
if (databurst == 0xEB) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, &IrrecoverableErrors, 3); //EMB
|
||||||
|
|
||||||
//dmr data header and multi block types (header, 1/2, 3/4, 1, UDT) - type 1
|
//dmr data header and multi block types (header, 1/2, 3/4, 1, UDT) - type 1
|
||||||
if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors);
|
if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors);
|
||||||
|
|||||||
376
src/dmr_flco.c
376
src/dmr_flco.c
@@ -12,7 +12,7 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
||||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t * IrrecoverableErrors, uint8_t type)
|
||||||
{
|
{
|
||||||
UNUSED(CRCCorrect);
|
UNUSED(CRCCorrect);
|
||||||
|
|
||||||
@@ -56,13 +56,43 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
|
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
|
||||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
||||||
|
|
||||||
|
//Kenwood w/ Scrambler Application on DMR (disable this if clash with other link control, its obscure)
|
||||||
|
uint8_t is_kenwood_sc = 0;
|
||||||
|
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && pf == 1 && fid == 0x20 && (so & 0x40) == 0x40)
|
||||||
|
{
|
||||||
|
pf = 0; //turn off PF flag
|
||||||
|
fid = 0; //unclear if this signals FID (or is cipher type for scrambler)
|
||||||
|
|
||||||
|
//NOTE: bit counter reset is handled after vc6 voice now
|
||||||
|
|
||||||
|
is_kenwood_sc = 1;
|
||||||
|
|
||||||
|
//if forcing a keystream, flip the encryption bit for this to unmute
|
||||||
|
if (state->ken_sc == 1)
|
||||||
|
so ^= 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kirisun
|
||||||
|
if (*IrrecoverableErrors == 0 && CRCCorrect == 1 && fid == 0x0A) //&& (so & 0x40) == 0x40
|
||||||
|
{
|
||||||
|
//disable late entry for DMRA, Flag 3 if encrypted, 0 if not
|
||||||
|
if (so & 0x40)
|
||||||
|
opts->dmr_le = 3;
|
||||||
|
else opts->dmr_le = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//read ahead a little to get this for the xpt flag
|
//read ahead a little to get this for the xpt flag
|
||||||
if (IrrecoverableErrors == 0 && flco == 0x09 && fid == 0x68)
|
if (*IrrecoverableErrors == 0 && flco == 0x09 && fid == 0x68)
|
||||||
{
|
{
|
||||||
sprintf (state->dmr_branding, "%s", " Hytera");
|
sprintf (state->dmr_branding, "%s", " Hytera");
|
||||||
sprintf (state->dmr_branding_sub, "XPT ");
|
sprintf (state->dmr_branding_sub, "XPT ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//bug fix for Hytera Enhanced link control (go by the checksum in the message)
|
||||||
|
//a good checksum will set IrrecoverableErrors back to zero
|
||||||
|
if (fid == 0x68 && flco == 0x02 && *IrrecoverableErrors == 0)
|
||||||
|
*IrrecoverableErrors = 1;
|
||||||
|
|
||||||
//look at the dmr_branding_sub for the XPT string
|
//look at the dmr_branding_sub for the XPT string
|
||||||
//branding sub is set at CSBK(68-3A and 3B), SLCO 8, and here on 0x09
|
//branding sub is set at CSBK(68-3A and 3B), SLCO 8, and here on 0x09
|
||||||
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
|
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
|
||||||
@@ -81,7 +111,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
goto END_FLCO;
|
goto END_FLCO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IrrecoverableErrors == 0)
|
if (*IrrecoverableErrors == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (slot == 0) state->dmr_flco = flco;
|
if (slot == 0) state->dmr_flco = flco;
|
||||||
@@ -98,14 +128,15 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
//Embedded Talker Alias Header Only (format and len storage)
|
//Embedded Talker Alias Header Only (format and len storage)
|
||||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
|
||||||
{
|
{
|
||||||
dmr_embedded_alias_header(opts, state, lc_bits);
|
is_alias = 1;
|
||||||
|
dmr_talker_alias_lc_header(opts, state, slot, lc_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Embedded Talker Alias Header (continuation) and Blocks
|
//Embedded Talker Alias Header (continuation) and Blocks
|
||||||
if ( (fid == 0 || fid == 0x68) && type == 3 && flco > 0x03 && flco < 0x08)
|
if ( (fid == 0 || fid == 0x68) && type == 3 && flco > 0x04 && flco < 0x08)
|
||||||
{
|
{
|
||||||
is_alias = 1;
|
is_alias = 1;
|
||||||
dmr_embedded_alias_blocks(opts, state, lc_bits);
|
dmr_talker_alias_lc_blocks(opts, state, slot, flco-5, lc_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Embedded GPS
|
//Embedded GPS
|
||||||
@@ -122,15 +153,19 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //don't believe so
|
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //don't believe so
|
||||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //
|
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //
|
||||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||||
|
if (flco == 0x07)
|
||||||
|
state->gi[slot] = 1;
|
||||||
|
else state->gi[slot] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Unknown CapMax/Moto Things
|
//Unknown CapMax/Moto Things
|
||||||
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
|
if (fid == 0x10 && (flco == 0x08 || flco == 0x28 || flco == 0x29))
|
||||||
{
|
{
|
||||||
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
|
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
|
||||||
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
|
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
|
||||||
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <- probably no SVC bits in the lc
|
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <- probably no SVC bits in the lc
|
||||||
//flco 0x28 has also been observed lately but the tg and src values don't match
|
//flco 0x28 has also been observed lately but the tg and src values don't match
|
||||||
|
//flco 0x29 just observed, similar pattern to 0x08 listed above
|
||||||
//another flco 0x10 does seem to match, so is probably capmax group call flco
|
//another flco 0x10 does seem to match, so is probably capmax group call flco
|
||||||
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
if (type == 1) fprintf (stderr, "%s \n", KCYN);
|
||||||
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
if (type == 2) fprintf (stderr, "%s \n", KCYN);
|
||||||
@@ -151,10 +186,18 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
|
|
||||||
//reset data header format storage
|
//reset data header format storage
|
||||||
state->data_header_format[slot] = 7;
|
state->data_header_format[slot] = 7;
|
||||||
|
//reset data header sap storage
|
||||||
|
state->data_header_sap[slot] = 0;
|
||||||
//flag off data header validity
|
//flag off data header validity
|
||||||
state->data_header_valid[slot] = 0;
|
state->data_header_valid[slot] = 0;
|
||||||
//flag off conf data flag
|
//flag off conf data flag
|
||||||
state->data_conf_data[slot] = 0;
|
state->data_conf_data[slot] = 0;
|
||||||
|
//reset padding
|
||||||
|
state->data_block_poc[slot] = 0;
|
||||||
|
//reset byte counter
|
||||||
|
state->data_byte_ctr[slot] = 0;
|
||||||
|
//reset ks start value
|
||||||
|
state->data_ks_start[slot] = 0;
|
||||||
|
|
||||||
goto END_FLCO;
|
goto END_FLCO;
|
||||||
}
|
}
|
||||||
@@ -276,8 +319,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
}
|
}
|
||||||
|
|
||||||
//unknown other manufacturer or OTA ENC, etc.
|
//unknown other manufacturer or OTA ENC, etc.
|
||||||
//removed tait from the list, added hytera 0x08
|
//removed tait from the list, added hytera 0x08, added Kirisun and KW Scrambler LC
|
||||||
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08)
|
if (fid != 0 && fid != 0x68 && fid != 0x10 && fid != 0x08 && fid != 0x0A && is_kenwood_sc == 0)
|
||||||
{
|
{
|
||||||
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
if (type == 1) fprintf (stderr, "%s \n", KYEL);
|
||||||
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
if (type == 2) fprintf (stderr, "%s \n", KYEL);
|
||||||
@@ -289,9 +332,75 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else //Look for Hytera PI LC (this may fail the FEC, but have a secondary checksum value)
|
||||||
|
{
|
||||||
|
if (fid == 0x68 && flco == 0x02)
|
||||||
|
{
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
uint8_t alg = (uint8_t)ConvertBitIntoBytes(&lc_bits[0], 8);
|
||||||
|
uint8_t key = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8);
|
||||||
|
unsigned long long int mi = (unsigned long long int)ConvertBitIntoBytes(&lc_bits[24], 40);
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot %d Alg: %02X; KEY ID: %02X; MI(40): %010llX;", slot+1, alg, key, mi);
|
||||||
|
fprintf (stderr, " Hytera Enhanced; ");
|
||||||
|
|
||||||
|
if (slot == 0 && state->R != 0)
|
||||||
|
fprintf (stderr, "Key: %010llX; ", state->R);
|
||||||
|
|
||||||
|
if (slot == 1 && state->RR != 0)
|
||||||
|
fprintf (stderr, "Key: %010llX; ", state->RR);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
checksum += (uint8_t)ConvertBitIntoBytes(&lc_bits[i*8], 8);
|
||||||
|
checksum &= 0xFF;
|
||||||
|
}
|
||||||
|
checksum = ~checksum & 0xFF;
|
||||||
|
checksum++;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " CHKSUM: %02X / %02X", checksum, (uint8_t)ConvertBitIntoBytes(&lc_bits[64], 8));
|
||||||
|
|
||||||
|
if (checksum == (uint8_t)ConvertBitIntoBytes(&lc_bits[64], 8))
|
||||||
|
{
|
||||||
|
if (slot == 0)
|
||||||
|
{
|
||||||
|
state->dmr_so |= 0x40; //OR the enc bit onto the SO
|
||||||
|
state->payload_algid = alg;
|
||||||
|
state->payload_keyid = key;
|
||||||
|
state->payload_mi = mi;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state->dmr_soR |= 0x40; //OR the enc bit onto the SO
|
||||||
|
state->payload_algidR = alg;
|
||||||
|
state->payload_keyidR = key;
|
||||||
|
state->payload_miR = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
//disable late entry for DMRA (hopefully, there aren't any systems running both DMRA and Hytera Enhanced mixed together)
|
||||||
|
opts->dmr_le = 2;
|
||||||
|
|
||||||
|
*IrrecoverableErrors = 0; //only set if checksum passes
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum == (uint8_t)ConvertBitIntoBytes(&lc_bits[64], 8))
|
||||||
|
// fprintf (stderr, " (Checksum Okay);");
|
||||||
|
{;}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KRED);
|
||||||
|
fprintf (stderr, " (Checksum Err);");
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
goto END_FLCO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
||||||
if(IrrecoverableErrors == 0 && is_alias == 0 && is_gps == 0)
|
if(*IrrecoverableErrors == 0 && is_alias == 0 && is_gps == 0)
|
||||||
{
|
{
|
||||||
//set overarching manufacturer in use when non-standard feature id set is up
|
//set overarching manufacturer in use when non-standard feature id set is up
|
||||||
if (fid != 0) state->dmr_mfid = fid;
|
if (fid != 0) state->dmr_mfid = fid;
|
||||||
@@ -329,39 +438,56 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
{
|
{
|
||||||
state->dmr_fid = 0;
|
state->dmr_fid = 0;
|
||||||
state->dmr_so = 0;
|
state->dmr_so = 0;
|
||||||
// state->lasttg = 0;
|
state->lasttg = 0;
|
||||||
// state->lastsrc = 0;
|
state->lastsrc = 0;
|
||||||
state->payload_algid = 0;
|
state->payload_algid = 0;
|
||||||
state->payload_mi = 0;
|
state->payload_mi = 0;
|
||||||
state->payload_keyid = 0;
|
state->payload_keyid = 0;
|
||||||
//reset gain
|
//reset gain
|
||||||
if (opts->floating_point == 1)
|
if (opts->floating_point == 1)
|
||||||
state->aout_gain = opts->audio_gain;
|
state->aout_gain = opts->audio_gain;
|
||||||
|
|
||||||
|
state->dmr_alias_block_len[0] = 0;
|
||||||
|
state->dmr_alias_char_size[0] = 0;
|
||||||
|
state->dmr_alias_format[0] = 0;
|
||||||
|
sprintf (state->generic_talker_alias[0], "%s", "");
|
||||||
|
// sprintf (state->event_history_s[0].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
||||||
|
memset (state->dmr_pdu_sf[0], 0, sizeof(state->dmr_pdu_sf[0]));
|
||||||
}
|
}
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
{
|
{
|
||||||
state->dmr_fidR = 0;
|
state->dmr_fidR = 0;
|
||||||
state->dmr_soR = 0;
|
state->dmr_soR = 0;
|
||||||
// state->lasttgR = 0;
|
state->lasttgR = 0;
|
||||||
// state->lastsrcR = 0;
|
state->lastsrcR = 0;
|
||||||
state->payload_algidR = 0;
|
state->payload_algidR = 0;
|
||||||
state->payload_miR = 0;
|
state->payload_miR = 0;
|
||||||
state->payload_keyidR = 0;
|
state->payload_keyidR = 0;
|
||||||
//reset gain
|
//reset gain
|
||||||
if (opts->floating_point == 1)
|
if (opts->floating_point == 1)
|
||||||
state->aout_gainR = opts->audio_gain;
|
state->aout_gainR = opts->audio_gain;
|
||||||
|
|
||||||
|
state->dmr_alias_block_len[1] = 0;
|
||||||
|
state->dmr_alias_char_size[1] = 0;
|
||||||
|
state->dmr_alias_format[1] = 0;
|
||||||
|
sprintf (state->generic_talker_alias[1], "%s", "");
|
||||||
|
// sprintf (state->event_history_s[1].Event_History_Items[0].alias, "%s", "BUMBLEBEETUNA");
|
||||||
|
memset (state->dmr_pdu_sf[1], 0, sizeof(state->dmr_pdu_sf[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//only assign this value here if not trunking
|
||||||
if (restchannel != state->dmr_rest_channel && restchannel != -1)
|
// if (opts->p25_trunk == 0) //may be safe to always do this now with code changes, will want to test at some point (tg hold w/ dual voice / slco may optimally need this set)
|
||||||
{
|
{
|
||||||
state->dmr_rest_channel = restchannel;
|
if (restchannel != state->dmr_rest_channel && restchannel != -1)
|
||||||
//assign to cc freq
|
|
||||||
if (state->trunk_chan_map[restchannel] != 0)
|
|
||||||
{
|
{
|
||||||
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
state->dmr_rest_channel = restchannel;
|
||||||
|
//assign to cc freq
|
||||||
|
// if (state->trunk_chan_map[restchannel] != 0)
|
||||||
|
// {
|
||||||
|
// state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,28 +510,35 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
|
|
||||||
else if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
else if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
|
||||||
{
|
{
|
||||||
sprintf (state->call_string[slot], " Cap+");
|
// sprintf (state->call_string[slot], " Cap+");
|
||||||
|
sprintf (state->call_string[slot], "%s","");
|
||||||
fprintf (stderr, "Cap+ ");
|
fprintf (stderr, "Cap+ ");
|
||||||
if (flco == 0x4)
|
if (flco == 0x4)
|
||||||
{
|
{
|
||||||
strcat (state->call_string[slot], " Grp");
|
// strcat (state->call_string[slot], " Grp");
|
||||||
|
sprintf (state->call_string[slot], " Group ");
|
||||||
fprintf (stderr, "Group ");
|
fprintf (stderr, "Group ");
|
||||||
|
state->gi[slot] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcat (state->call_string[slot], " Pri");
|
// strcat (state->call_string[slot], " Pri");
|
||||||
|
sprintf (state->call_string[slot], " Private ");
|
||||||
fprintf (stderr, "Private ");
|
fprintf (stderr, "Private ");
|
||||||
|
state->gi[slot] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (flco == 0x3) //UU_V_Ch_Usr
|
else if (flco == 0x3) //UU_V_Ch_Usr
|
||||||
{
|
{
|
||||||
sprintf (state->call_string[slot], " Private ");
|
sprintf (state->call_string[slot], " Private ");
|
||||||
fprintf (stderr, "Private ");
|
fprintf (stderr, "Private ");
|
||||||
|
state->gi[slot] = 1;
|
||||||
}
|
}
|
||||||
else //Grp_V_Ch_Usr -- still valid on hytera VLC
|
else //Grp_V_Ch_Usr -- still valid on hytera VLC
|
||||||
{
|
{
|
||||||
sprintf (state->call_string[slot], " Group ");
|
sprintf (state->call_string[slot], " Group ");
|
||||||
fprintf (stderr, "Group ");
|
fprintf (stderr, "Group ");
|
||||||
|
state->gi[slot] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(so & 0x80)
|
if(so & 0x80)
|
||||||
@@ -445,18 +578,25 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
|
|
||||||
//if group doesn't exist, or isn't locked out, then do so now.
|
//if group doesn't exist, or isn't locked out, then do so now.
|
||||||
if (lo == 0)
|
if (lo == 0)
|
||||||
{
|
{ //changing from DE to B to fit the rest of the lockout logic ("Buzzer Fix")
|
||||||
state->group_array[state->group_tally].groupNumber = target;
|
state->group_array[state->group_tally].groupNumber = target;
|
||||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO");
|
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO");
|
||||||
sprintf (gm, "%s", "DE");
|
sprintf (gm, "%s", "B");
|
||||||
sprintf (gn, "%s", "ENC LO");
|
sprintf (gn, "%s", "ENC LO");
|
||||||
state->group_tally++;
|
state->group_tally++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//run a watchdog here so we can update this with the crypto variables and ENC LO
|
||||||
|
if (target != 0 && lo == 0)
|
||||||
|
{
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].internal_str, "Target: %d; has been locked out; Encryption Lock Out Enabled.", target);
|
||||||
|
watchdog_event_current(opts, state, slot);
|
||||||
|
}
|
||||||
|
|
||||||
//Craft a fake CSBK pdu send it to run as a p_clear to return to CC if available
|
//Craft a fake CSBK pdu send it to run as a p_clear to return to CC if available
|
||||||
uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 255;
|
uint8_t dummy[12]; uint8_t* dbits; memset (dummy, 0, sizeof(dummy)); dummy[0] = 46; dummy[1] = 255;
|
||||||
if ( (strcmp(gm, "DE") == 0) && (strcmp(gn, "ENC LO") == 0) ) //&& (opts->trunk_tune_data_calls == 0)
|
if ( (strcmp(gm, "B") == 0) && (strcmp(gn, "ENC LO") == 0) ) //&& (opts->trunk_tune_data_calls == 0)
|
||||||
dmr_cspdu (opts, state, dbits, dummy, 1, 0);
|
dmr_cspdu (opts, state, dbits, dummy, 1, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -523,10 +663,22 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
}
|
}
|
||||||
|
|
||||||
//should rework this back into the upper portion
|
//should rework this back into the upper portion
|
||||||
|
if (fid == 0x0A) fprintf (stderr, "Kirisun ");
|
||||||
if (fid == 0x68) fprintf (stderr, "Hytera ");
|
if (fid == 0x68) fprintf (stderr, "Hytera ");
|
||||||
if (is_xpt) fprintf (stderr, "XPT ");
|
if (is_xpt) fprintf (stderr, "XPT ");
|
||||||
if (fid == 0x68 && flco == 0x00) fprintf (stderr, "Group ");
|
if (fid == 0x68 && flco == 0x00)
|
||||||
if (fid == 0x68 && flco == 0x03) fprintf (stderr, "Private ");
|
{
|
||||||
|
fprintf (stderr, "Group ");
|
||||||
|
state->gi[slot] = 0;
|
||||||
|
}
|
||||||
|
if (fid == 0x68 && flco == 0x03)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Private ");
|
||||||
|
state->gi[slot] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_kenwood_sc)
|
||||||
|
fprintf(stderr, "Kenwood Scrambler ");
|
||||||
|
|
||||||
fprintf(stderr, "Call ");
|
fprintf(stderr, "Call ");
|
||||||
|
|
||||||
@@ -607,6 +759,40 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot == 0 && state->payload_algid == 0x02 && state->R != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, "Key: %010llX ", state->R);
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == 1 && state->payload_algidR == 0x02 && state->RR != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, "Key: %010llX ", state->RR);
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == 0 && (state->payload_algid == 0x25 || state->payload_algid == 0x24) && state->aes_key_loaded[0] == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n ");
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, "Key: %016llX %016llX ", state->A1[0], state->A2[0]);
|
||||||
|
if (state->payload_algid == 0x25)
|
||||||
|
fprintf (stderr, "%016llX %016llX", state->A3[0], state->A4[0]);
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == 1 && (state->payload_algidR == 0x25 || state->payload_algidR == 0x24) && state->aes_key_loaded[1] == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n ");
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, "Key: %016llX %016llX ", state->A1[1], state->A2[1]);
|
||||||
|
if (state->payload_algidR == 0x25)
|
||||||
|
fprintf (stderr, "%016llX %016llX", state->A3[1], state->A4[1]);
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
END_FLCO:
|
END_FLCO:
|
||||||
@@ -620,7 +806,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IrrecoverableErrors != 0)
|
if(*IrrecoverableErrors != 0)
|
||||||
{
|
{
|
||||||
if (type != 3) fprintf (stderr, "\n");
|
if (type != 3) fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KRED);
|
fprintf (stderr, "%s", KRED);
|
||||||
@@ -819,7 +1005,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
uint8_t model = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 2);
|
uint8_t model = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 2);
|
||||||
uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12);
|
uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12);
|
||||||
uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch
|
uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch
|
||||||
uint8_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511
|
uint16_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511
|
||||||
UNUSED(netsite);
|
UNUSED(netsite);
|
||||||
|
|
||||||
uint16_t net = 0;
|
uint16_t net = 0;
|
||||||
@@ -986,7 +1172,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
|
||||||
|
|
||||||
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
//if using rigctl we can set an unknown cc frequency by polling rigctl for the current frequency
|
||||||
if (opts->use_rigctl == 1 && state->p25_cc_freq == 0) //if not set from channel map 0
|
if (opts->use_rigctl == 1 && opts->p25_is_tuned == 0)
|
||||||
{
|
{
|
||||||
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
ccfreq = GetCurrentFreq (opts->rigctl_sockfd);
|
||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||||
@@ -999,26 +1185,44 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if on Con+ control channel and no activity in this window
|
||||||
|
if ( (time(NULL) - state->last_vc_sync_time) > 2 ) //may use last_cc_sync_time instead
|
||||||
|
rotate_symbol_out_file(opts, state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (slco == 0xF)
|
else if (slco == 0xF)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest LSN: %d - RS: %02X", capsite, restchannel, cap_reserved);
|
||||||
//assign to cc freq if available
|
|
||||||
if (state->trunk_chan_map[restchannel] != 0)
|
|
||||||
{
|
|
||||||
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
|
||||||
}
|
|
||||||
|
|
||||||
//extra handling for TG hold while trunking enabled
|
//extra handling for TG hold while trunking enabled
|
||||||
if (state->tg_hold != 0 && opts->p25_trunk == 1)
|
if (state->tg_hold != 0 && opts->p25_trunk == 1) //logic seems to be fixed now for new rest lsn logic and other considerations
|
||||||
{
|
{
|
||||||
//if both slots are voice,
|
//debug
|
||||||
if (state->dmrburstL == 16 && state->dmrburstR == 16)
|
// fprintf (stderr, " TG HOLD Both Slots Busy Check; ");
|
||||||
|
|
||||||
|
//if both slots have some cobination of vlc, pi, voice, or tlc
|
||||||
|
int busy = 0;
|
||||||
|
if ( (state->dmrburstL == 16 || state->dmrburstL == 0 || state->dmrburstL == 1 || state->dmrburstL == 2) &&
|
||||||
|
(state->dmrburstR == 16 || state->dmrburstR == 0 || state->dmrburstR == 1 || state->dmrburstR == 2)) busy = 1;
|
||||||
|
if (busy)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " Busy; ");
|
||||||
|
|
||||||
//but nether is the TG on hold
|
//but nether is the TG on hold
|
||||||
if ( (state->tg_hold != state->lasttg) && (state->tg_hold != state->lasttgR) )
|
if ( (state->tg_hold != state->lasttg) && (state->tg_hold != state->lasttgR) )
|
||||||
{
|
{
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " Neither Slot is TG on Hold; ");
|
||||||
|
|
||||||
|
//assign to cc freq if available -- move to right before needed for new logic on rest lsn
|
||||||
|
if (state->trunk_chan_map[restchannel] != 0)
|
||||||
|
{
|
||||||
|
state->p25_cc_freq = state->trunk_chan_map[restchannel];
|
||||||
|
}
|
||||||
|
|
||||||
//tune to the current rest channel so we can observe its channel status csbks for the TG on hold
|
//tune to the current rest channel so we can observe its channel status csbks for the TG on hold
|
||||||
if (state->p25_cc_freq != 0)
|
if (state->p25_cc_freq != 0)
|
||||||
{
|
{
|
||||||
@@ -1131,95 +1335,3 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//externalize embedded alias to keep the flco function relatively clean
|
|
||||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|
||||||
{
|
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
|
||||||
uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2);
|
|
||||||
uint8_t len;
|
|
||||||
|
|
||||||
//this len seems to pertain to number of blocks? not bit len.
|
|
||||||
//len = (uint8_t)ConvertBitIntoBytes(&lc_bits[18], 5);
|
|
||||||
|
|
||||||
if (format == 0) len = 7;
|
|
||||||
else if (format == 1 || format == 2) len = 8;
|
|
||||||
else len = 16;
|
|
||||||
|
|
||||||
state->dmr_alias_format[slot] = format;
|
|
||||||
state->dmr_alias_len[slot] = len;
|
|
||||||
|
|
||||||
//fprintf (stderr, "F: %d L: %d - ", format, len);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|
||||||
{
|
|
||||||
UNUSED(opts);
|
|
||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
|
||||||
fprintf (stderr, " Embedded Alias: ");
|
|
||||||
uint8_t slot = state->currentslot;
|
|
||||||
uint8_t block = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //FLCO equals block number
|
|
||||||
uint8_t format = state->dmr_alias_format[slot]; //0=7-bit; 1=ISO8; 2=UTF-8; 3=UTF16BE
|
|
||||||
uint8_t len = state->dmr_alias_len[slot];
|
|
||||||
uint8_t start; //starting position depends on context of block and format
|
|
||||||
UNUSED(format);
|
|
||||||
|
|
||||||
//Cap Max Variation
|
|
||||||
uint8_t fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8);
|
|
||||||
if (fid == 0x10) block = block - 0x10; //CapMax adds 0x10 to its FLCO (block num) in its Embedded Aliasing
|
|
||||||
|
|
||||||
//there is some issue with the next three lines of code that prevent proper assignments, not sure what.
|
|
||||||
//if (block > 4) start = 16;
|
|
||||||
//else if (block == 4 && format > 0) start = 23; //8-bit and 16-bit chars
|
|
||||||
//else start = 24;
|
|
||||||
|
|
||||||
//forcing start to 16 make it work on 8-bit alias, len seems okay when set off of format
|
|
||||||
start = 16;
|
|
||||||
len = 8;
|
|
||||||
|
|
||||||
// fprintf (stderr, "block: %d start: %d len: %d ", block, start, len);
|
|
||||||
|
|
||||||
//all may not be used depending on format, len, start.
|
|
||||||
uint16_t A0, A1, A2, A3, A4, A5, A6;
|
|
||||||
|
|
||||||
//sanity check
|
|
||||||
if (block > 7) block = 4; //prevent oob array (although we should never get here)
|
|
||||||
|
|
||||||
if (len > 6) //if not greater than zero, then the header hasn't arrived yet
|
|
||||||
{
|
|
||||||
A0 = 0; A1 = 0; A2 = 0; A3 = 0; A4 = 0; A5 = 0; A6 = 0; //NULL ASCII Characters
|
|
||||||
A0 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*0], len);
|
|
||||||
A1 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*1], len);
|
|
||||||
A2 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*2], len);
|
|
||||||
A3 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*3], len);
|
|
||||||
A4 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*4], len);
|
|
||||||
A5 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*5], len);
|
|
||||||
A6 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*6], len);
|
|
||||||
|
|
||||||
//just going to assign the usual ascii set here to prevent 'naughty' characters, sans diacriticals
|
|
||||||
if (A0 > 0x19 && A0 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][0], "%c", A0);
|
|
||||||
if (A1 > 0x19 && A1 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][1], "%c", A1);
|
|
||||||
if (A2 > 0x19 && A2 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][2], "%c", A2);
|
|
||||||
if (A3 > 0x19 && A3 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][3], "%c", A3);
|
|
||||||
if (A4 > 0x19 && A4 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][4], "%c", A4);
|
|
||||||
if (A5 > 0x19 && A5 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][5], "%c", A5);
|
|
||||||
if (A6 > 0x19 && A6 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][6], "%c", A6);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 7; j++)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s", state->dmr_alias_block_segment[slot][i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else fprintf (stderr, "Missing Header Block Format and Len Data");
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
235
src/dmr_le.c
235
src/dmr_le.c
@@ -14,23 +14,6 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
|
|||||||
|
|
||||||
uint8_t slot = state->currentslot;
|
uint8_t slot = state->currentslot;
|
||||||
|
|
||||||
//enforce RC4 due to missing PI header, but with valid SVC Opts
|
|
||||||
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
|
|
||||||
//due to multiple signalling occurring inside of it, depending on system type
|
|
||||||
if (state->M == 0x21)
|
|
||||||
{
|
|
||||||
if (slot == 0 && state->dmr_so & 0x40)
|
|
||||||
{
|
|
||||||
state->payload_algid = 0x21;
|
|
||||||
state->payload_keyid = 0xFF;
|
|
||||||
}
|
|
||||||
if (slot == 1 && state->dmr_soR & 0x40)
|
|
||||||
{
|
|
||||||
state->payload_algidR = 0x21;
|
|
||||||
state->payload_keyidR = 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//collect our fragments and place them into storage
|
//collect our fragments and place them into storage
|
||||||
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
||||||
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
|
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
|
||||||
@@ -90,7 +73,7 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mi_final = 0;
|
unsigned long long int mi_final = 0;
|
||||||
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
||||||
|
|
||||||
mi_crc_ext = (uint8_t)ConvertBitIntoBytes(&mi_bits[32], 4);
|
mi_crc_ext = (uint8_t)ConvertBitIntoBytes(&mi_bits[32], 4);
|
||||||
@@ -108,42 +91,99 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
|||||||
if (state->payload_mi != mi_final)
|
if (state->payload_mi != mi_final)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_mi, mi_final);
|
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08llX : %08llX ", state->payload_mi, mi_final);
|
||||||
if (mi_crc_ok == 1) state->payload_mi = mi_final;
|
if (mi_crc_ok == 1) state->payload_mi = mi_final;
|
||||||
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||||
else fprintf (stderr, "(CRC ERR)");
|
else fprintf (stderr, "(CRC ERR)");
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
//run afterwards, or le verification won't match up properly
|
|
||||||
if (state->payload_algid != 0x21)
|
//run expansions afterwards, or le verification won't match up properly
|
||||||
|
|
||||||
|
//DES1
|
||||||
|
if (state->payload_algid == 0x22)
|
||||||
{
|
{
|
||||||
LFSR64 (state);
|
LFSR64 (state);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//AES-128 or AES-256
|
||||||
|
if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||||
|
{
|
||||||
|
LFSR128d (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (slot == 1 && state->payload_algidR != 0)
|
if (slot == 1 && state->payload_algidR != 0)
|
||||||
{
|
{
|
||||||
if (state->payload_miR != mi_final)
|
if (state->payload_miR != mi_final)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_miR, mi_final);
|
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08llX : %08llX ", state->payload_miR, mi_final);
|
||||||
if (mi_crc_ok == 1) state->payload_miR = mi_final;
|
if (mi_crc_ok == 1) state->payload_miR = mi_final;
|
||||||
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
|
||||||
else fprintf (stderr, "(CRC ERR)");
|
else fprintf (stderr, "(CRC ERR)");
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
//run afterwards, or le verification won't match up properly
|
|
||||||
if (state->payload_algidR != 0x21)
|
//run expansions afterwards, or le verification won't match up properly
|
||||||
|
|
||||||
|
//DES1
|
||||||
|
if (state->payload_algidR == 0x22)
|
||||||
{
|
{
|
||||||
LFSR64 (state);
|
LFSR64 (state);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//AES-128 or AES-256
|
||||||
|
if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||||
|
{
|
||||||
|
LFSR128d (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//run LFSR even if golay fails
|
||||||
|
else if (slot == 0 && state->payload_algid != 0)
|
||||||
|
{
|
||||||
|
//DES1
|
||||||
|
if (state->payload_algid == 0x22)
|
||||||
|
{
|
||||||
|
LFSR64 (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//AES-128 or AES-256
|
||||||
|
if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||||
|
{
|
||||||
|
LFSR128d (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (slot == 1 && state->payload_algidR != 0)
|
||||||
|
{
|
||||||
|
//DES1
|
||||||
|
if (state->payload_algidR == 0x22)
|
||||||
|
{
|
||||||
|
LFSR64 (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//AES-128 or AES-256
|
||||||
|
if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||||
|
{
|
||||||
|
LFSR128d (state);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
||||||
@@ -164,7 +204,37 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
|||||||
LFSR (state);
|
LFSR (state);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
//LFSR64 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
|
|
||||||
|
//LFSR64/128 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
|
||||||
|
|
||||||
|
if (state->payload_algid == 0x02)
|
||||||
|
{
|
||||||
|
state->DMRvcL = 0;
|
||||||
|
//LFSR already calculated, just dump it now
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 1");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
||||||
|
fprintf (stderr, " MI(40): %010llX;", state->payload_mi);
|
||||||
|
fprintf (stderr, " Hytera Enhanced;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->payload_algid == 0x35 || state->payload_algid == 0x36 || state->payload_algid == 0x37)
|
||||||
|
{
|
||||||
|
state->DMRvcL = 0;
|
||||||
|
state->payload_mi = kirisun_lfsr(state->payload_mi);
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 1");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
||||||
|
fprintf (stderr, " MI(32): %08llX;", state->payload_mi);
|
||||||
|
fprintf (stderr, " Kirisun");
|
||||||
|
if (state->payload_algid == 0x36)
|
||||||
|
fprintf (stderr, " Advanced;");
|
||||||
|
else if (state->payload_algid == 0x37)
|
||||||
|
fprintf (stderr, " Universal;");
|
||||||
|
else fprintf (stderr, " Encryption;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
@@ -181,7 +251,37 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
|||||||
LFSR (state);
|
LFSR (state);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
//LFSR64 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
|
|
||||||
|
//LFSR64/128 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
|
||||||
|
|
||||||
|
if (state->payload_algidR == 0x02)
|
||||||
|
{
|
||||||
|
state->DMRvcR = 0;
|
||||||
|
//LFSR already calculated, just dump it now
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 2");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
||||||
|
fprintf (stderr, " MI(40): %010llX;", state->payload_miR);
|
||||||
|
fprintf (stderr, " Hytera Enhanced;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->payload_algidR == 0x35 || state->payload_algidR == 0x36 || state->payload_algidR == 0x37)
|
||||||
|
{
|
||||||
|
state->DMRvcR = 0;
|
||||||
|
state->payload_miR = kirisun_lfsr(state->payload_miR);
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 2");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
||||||
|
fprintf (stderr, " MI(32): %08llX;", state->payload_miR);
|
||||||
|
fprintf (stderr, " Kirisun");
|
||||||
|
if (state->payload_algidR == 0x36)
|
||||||
|
fprintf (stderr, " Advanced;");
|
||||||
|
else if (state->payload_algidR == 0x37)
|
||||||
|
fprintf (stderr, " Universal;");
|
||||||
|
else fprintf (stderr, " Encryption;");
|
||||||
|
fprintf (stderr, "%s\n", KNRM);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,8 +295,8 @@ void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
|
|||||||
state->dropR = 256;
|
state->dropR = 256;
|
||||||
state->DMRvcL = 0;
|
state->DMRvcL = 0;
|
||||||
state->DMRvcR = 0;
|
state->DMRvcR = 0;
|
||||||
state->payload_miP = 0;
|
// state->payload_miP = 0; //running these clears out before we can create a new keystream
|
||||||
state->payload_miN = 0;
|
// state->payload_miN = 0; //running these clears out before we can create a new keystream
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
|
||||||
@@ -252,7 +352,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
crc_extracted = crc_extracted | sbrc_return[i+4];
|
crc_extracted = crc_extracted | sbrc_return[i+4];
|
||||||
}
|
}
|
||||||
crc_extracted = crc_extracted ^ 0x7A;
|
crc_extracted = crc_extracted ^ 0x7A;
|
||||||
crc_computed = crc7((uint8_t *) sbrc_return, 7);
|
crc_computed = crc7((uint8_t *) sbrc_return, 4); //#187 fix
|
||||||
if (crc_extracted == crc_computed) crc7_okay = 1;
|
if (crc_extracted == crc_computed) crc7_okay = 1;
|
||||||
}
|
}
|
||||||
else //if (txi == 1) //if TXI -- but TXI systems also carry the non-crc protected ENC identifiers
|
else //if (txi == 1) //if TXI -- but TXI systems also carry the non-crc protected ENC identifiers
|
||||||
@@ -307,6 +407,41 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
|
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
|
||||||
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
|
||||||
|
|
||||||
|
//Kirisun Placeholder
|
||||||
|
if (opts->dmr_le == 3)
|
||||||
|
{
|
||||||
|
if (irr_err != 0)
|
||||||
|
{
|
||||||
|
uint32_t sbrcpl = 0;
|
||||||
|
for(i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
sbrcpl = sbrcpl << 1;
|
||||||
|
sbrcpl |= sbrc_interleaved[i] & 1;
|
||||||
|
}
|
||||||
|
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "%s SLOT %d SB/RC (FEC ERR) E:%d; I:%08X D:%03X; %s ", KRED, slot+1, irr_err, sbrcpl, sbrc_hex, KNRM);
|
||||||
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
else if (irr_err == 0 && sbrc_hex != 0) //first batch had sbrc_hex 0x5F1, second batch had 0x5E1 instead, what changed?
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
fprintf (stderr, " Slot %d", state->currentslot+1);
|
||||||
|
fprintf (stderr, " DMR LE SB Kirisun Encryption Identifier;");
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
if (state->payload_algid == 0 && state->dmr_so & 0x40)
|
||||||
|
state->payload_algid = 0x35; //placeholder value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (state->payload_algidR == 0 && state->dmr_soR & 0x40)
|
||||||
|
state->payload_algidR = 0x35; //placeholder value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->dmr_le == 1)
|
if (opts->dmr_le == 1)
|
||||||
{
|
{
|
||||||
if (irr_err != 0)
|
if (irr_err != 0)
|
||||||
@@ -323,7 +458,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
}
|
}
|
||||||
if (irr_err == 0)
|
if (irr_err == 0)
|
||||||
{
|
{
|
||||||
if (sbrc_hex == 0) ; //NULL, do nothing
|
if (sbrc_hex == 0 && crc7_okay == 0) ; //NULL Single Burst, do nothing (changed to allow the 0 value of RC below to trigger)
|
||||||
|
|
||||||
//else if (placeholder for future conditions)
|
//else if (placeholder for future conditions)
|
||||||
// {
|
// {
|
||||||
@@ -332,7 +467,20 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
|
|
||||||
else if (crc7_okay == 1)
|
else if (crc7_okay == 1)
|
||||||
{
|
{
|
||||||
//do something with the reverse channel information
|
//decode the reverse channel information ETSI TS 102 361-4 V1.12.1 (2023-07) p 103 Table 6.32: MS Reverse Channel (RC) Command Information Elements
|
||||||
|
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "%s", KCYN);
|
||||||
|
sbrc_hex = sbrc_hex >> 7; //set value to its 4-bit form
|
||||||
|
if (sbrc_hex == 0) fprintf (stderr, " RC: Increase Power By One Step;");
|
||||||
|
else if (sbrc_hex == 1) fprintf (stderr, " RC: Decrease Power By One Step;");
|
||||||
|
else if (sbrc_hex == 2) fprintf (stderr, " RC: Set Power To Highest;");
|
||||||
|
else if (sbrc_hex == 3) fprintf (stderr, " RC: Set Power To Lowest;");
|
||||||
|
else if (sbrc_hex == 4) fprintf (stderr, " RC: Cease Transmission Command;");
|
||||||
|
else if (sbrc_hex == 5) fprintf (stderr, " RC: Cease Transmission Request;");
|
||||||
|
else fprintf (stderr, " RC: Reserved %02X;", sbrc_hex);
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
// if (opts->payload == 1)
|
||||||
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//if the call is interruptable (TXI) and the crc3 is okay and TXI Opcode
|
//if the call is interruptable (TXI) and the crc3 is okay and TXI Opcode
|
||||||
@@ -370,12 +518,16 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
|
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
|
||||||
{
|
{
|
||||||
//if we aren't forcing a particular alg or privacy key set
|
//if we aren't forcing a particular alg or privacy key set
|
||||||
if (state->M == 0)
|
if (state->forced_alg_id == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: %02X; KEY ID: %02X;", alg + 0x20, key);
|
||||||
|
if (alg == 1) fprintf (stderr, " RC4;");
|
||||||
|
if (alg == 2) fprintf (stderr, " DES;");
|
||||||
|
if (alg == 4) fprintf (stderr, " AES128;");
|
||||||
|
if (alg == 5) fprintf (stderr, " AES256;");
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
if (state->payload_keyid != key)
|
if (state->payload_keyid != key)
|
||||||
@@ -392,12 +544,12 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
|
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
|
||||||
{
|
{
|
||||||
//if we aren't forcing a particular alg or privacy key set
|
//if we aren't forcing a particular alg or privacy key set
|
||||||
if (state->M == 0)
|
if (state->forced_alg_id == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
fprintf (stderr, "%s", KCYN);
|
fprintf (stderr, "%s", KCYN);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
|
fprintf (stderr, " DMR LE SB ALG ID: %02X; KEY ID: %02X;", alg + 0x20, key);
|
||||||
fprintf (stderr, "%s ", KNRM);
|
fprintf (stderr, "%s ", KNRM);
|
||||||
if (opts->payload == 1) fprintf (stderr, "\n");
|
if (opts->payload == 1) fprintf (stderr, "\n");
|
||||||
if (state->payload_keyidR != key)
|
if (state->payload_keyidR != key)
|
||||||
@@ -416,17 +568,16 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
|||||||
|
|
||||||
SBRC_END:
|
SBRC_END:
|
||||||
|
|
||||||
//'DSP' output to file -- only RC, or RC and SB?
|
//'DSP' output to file -- SB and RC
|
||||||
if (power == 1 && opts->use_dsp_output == 1 && sbrc_hex != 0) //if not NULL
|
if (opts->use_dsp_output == 1)
|
||||||
{
|
{
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
pFile = fopen (opts->dsp_out_file, "a");
|
pFile = fopen (opts->dsp_out_file, "a");
|
||||||
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is RC designation value
|
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is SB and RC designation value
|
||||||
int k = 0;
|
for (i = 0; i < 12; i++) //48 bits (includes CC, PPI, LCSS, and QR)
|
||||||
for (i = 0; i < 24; i++) //12 bytes, SB or RC
|
// for (i = 2; i < 10; i++) //32 bits (only SB/RC Data and its PC/H)
|
||||||
{
|
{
|
||||||
//check to see if k++ starts at zero, or at 1
|
uint8_t sbrc_nib = (state->dmr_embedded_signalling[slot][5][(i*4)+0] << 3) | (state->dmr_embedded_signalling[slot][5][(i*4)+1] << 2) | (state->dmr_embedded_signalling[slot][5][(i*4)+2] << 1) | (state->dmr_embedded_signalling[slot][5][(i*4)+3] << 0);
|
||||||
int sbrc_nib = (state->dmr_embedded_signalling[slot][5][k++] << 3) | (state->dmr_embedded_signalling[slot][5][k++] << 2) | (state->dmr_embedded_signalling[slot][5][k++] << 1) | (state->dmr_embedded_signalling[slot][5][k++] << 0);
|
|
||||||
fprintf (pFile, "%X", sbrc_nib);
|
fprintf (pFile, "%X", sbrc_nib);
|
||||||
}
|
}
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|||||||
297
src/dmr_ms.c
297
src/dmr_ms.c
@@ -9,10 +9,14 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include "dmr_const.h"
|
#include "dmr_const.h"
|
||||||
|
|
||||||
|
// #define PRINT_AMBE72 //enable to view 72-bit AMBE codewords
|
||||||
|
|
||||||
//A subroutine for processing MS voice
|
//A subroutine for processing MS voice
|
||||||
void dmrMS (dsd_opts * opts, dsd_state * state)
|
void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * timestr = getTimeC();
|
||||||
|
|
||||||
int i, j, dibit;
|
int i, j, dibit;
|
||||||
char ambe_fr[4][24];
|
char ambe_fr[4][24];
|
||||||
char ambe_fr2[4][24];
|
char ambe_fr2[4][24];
|
||||||
@@ -25,9 +29,12 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t m3[4][24];
|
uint8_t m3[4][24];
|
||||||
|
|
||||||
const int *w, *x, *y, *z;
|
const int *w, *x, *y, *z;
|
||||||
char sync[25];
|
|
||||||
char syncdata[48];
|
uint8_t syncdata[48];
|
||||||
uint8_t EmbeddedSignalling[16];
|
memset (syncdata, 0, sizeof(syncdata));
|
||||||
|
|
||||||
|
uint8_t emb_pdu[16];
|
||||||
|
memset (emb_pdu, 0, sizeof(emb_pdu));
|
||||||
|
|
||||||
//cach
|
//cach
|
||||||
char cachdata[25];
|
char cachdata[25];
|
||||||
@@ -36,8 +43,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t tact_bits[7];
|
uint8_t tact_bits[7];
|
||||||
|
|
||||||
uint8_t tact_okay = 0;
|
uint8_t tact_okay = 0;
|
||||||
uint8_t EmbeddedSignallingOk = 0;
|
uint8_t emb_ok = 0;
|
||||||
UNUSED(EmbeddedSignallingOk);
|
UNUSED(emb_ok);
|
||||||
|
|
||||||
uint8_t internalslot;
|
uint8_t internalslot;
|
||||||
uint8_t vc;
|
uint8_t vc;
|
||||||
@@ -52,22 +59,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
uint8_t dummy_bits[196];
|
uint8_t dummy_bits[196];
|
||||||
memset (dummy_bits, 0, sizeof (dummy_bits));
|
memset (dummy_bits, 0, sizeof (dummy_bits));
|
||||||
|
|
||||||
//add time to mirror printFrameSync
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
vc = 2;
|
vc = 2;
|
||||||
|
|
||||||
//Hardset variables for MS/Mono
|
//Hardset variables for MS/Mono
|
||||||
@@ -167,10 +158,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||||
|
|
||||||
sync[i] = (dibit | 1) + 48;
|
|
||||||
|
|
||||||
// load the superframe to do embedded signal processing
|
// load the superframe to do embedded signal processing
|
||||||
if(vc > 1) //grab on vc1 values 2-5 B C D and E
|
if(vc > 1) //grab on vc2 values 2-5 B C D E, and F
|
||||||
{
|
{
|
||||||
state->dmr_embedded_signalling[internalslot][vc-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
state->dmr_embedded_signalling[internalslot][vc-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||||
state->dmr_embedded_signalling[internalslot][vc-1][i*2+1] = (1 & dibit); // bit 0
|
state->dmr_embedded_signalling[internalslot][vc-1][i*2+1] = (1 & dibit); // bit 0
|
||||||
@@ -178,35 +167,27 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sync[24] = 0;
|
//Kirisun Check VC-F for Enc Identifiers -- has bad fec, unless its loaded differently
|
||||||
|
//SEE: https://patents.google.com/patent/CN102307075A/en?q=(kirisun)&q=(dmr)&oq=kirisun
|
||||||
|
// if (opts->dmr_le == 3 && vc == 6)
|
||||||
|
// {
|
||||||
|
// bool kokay = 0;
|
||||||
|
// // kokay = Golay_24_12_decode(syncdata);
|
||||||
|
// unsigned long long int kirisun = (unsigned long long int)ConvertBitIntoBytes(&syncdata[0], 48);
|
||||||
|
// fprintf (stderr, "Kiri: %012llX; Golay Okay: %d; \n", kirisun, kokay);
|
||||||
|
// }
|
||||||
|
|
||||||
//test for RC sync pattern in MS sourced audio
|
for(i = 0; i < 8; i++) emb_pdu[i + 0] = syncdata[i];
|
||||||
if ( strcmp (sync, DMR_RC_DATA_SYNC) == 0)
|
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||||
|
|
||||||
|
emb_ok = -1;
|
||||||
|
if(QR_16_7_6_decode(emb_pdu))
|
||||||
{
|
{
|
||||||
state->dmr_ms_rc = 1;
|
emb_ok = 1;
|
||||||
fprintf (stderr, "%s ", getTime());
|
cc = ((emb_pdu[0] << 3) + (emb_pdu[1] << 2) + (emb_pdu[2] << 1) + emb_pdu[3]);
|
||||||
if (opts->inverted_dmr == 0)
|
power = emb_pdu[4];
|
||||||
{
|
lcss = ((emb_pdu[5] << 1) + emb_pdu[6]);
|
||||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
state->dmr_color_code = state->color_code = cc;
|
||||||
}
|
|
||||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
|
||||||
|
|
||||||
fprintf (stderr, "| RC ");
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
|
||||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
|
||||||
|
|
||||||
EmbeddedSignallingOk = -1;
|
|
||||||
if(QR_16_7_6_decode(EmbeddedSignalling))
|
|
||||||
{
|
|
||||||
EmbeddedSignallingOk = 1;
|
|
||||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
|
||||||
power = EmbeddedSignalling[4];
|
|
||||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||||
@@ -275,40 +256,39 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
if (state->dmr_ms_rc == 0)
|
if (state->tyt_bp == 1)
|
||||||
{
|
{
|
||||||
if (state->directmode == 0)
|
tyt16_ambe2_codeword_keystream(state, ambe_fr, 0);
|
||||||
{
|
tyt16_ambe2_codeword_keystream(state, ambe_fr2, 1);
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->csi_ee == 1)
|
||||||
|
{
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PRINT_AMBE72
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
|
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
|
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
|
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
||||||
|
|
||||||
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
||||||
if (opts->floating_point == 0)
|
if (opts->floating_point == 0)
|
||||||
{
|
{
|
||||||
@@ -326,6 +306,10 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (vc == 6)
|
if (vc == 6)
|
||||||
{
|
{
|
||||||
|
//this needs to run prior to embedded link control
|
||||||
|
if (state->payload_algid == 0x02)
|
||||||
|
hytera_enhanced_alg_refresh(state);
|
||||||
|
|
||||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||||
//check the single burst/reverse channel opportunity
|
//check the single burst/reverse channel opportunity
|
||||||
dmr_sbrc (opts, state, power);
|
dmr_sbrc (opts, state, power);
|
||||||
@@ -335,7 +319,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//collect the mi fragment
|
//collect the mi fragment
|
||||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
if (opts->dmr_le != 2) //if not Hytera Enhanced
|
||||||
|
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
||||||
|
|
||||||
//errors in ms/mono since we skip the other slot
|
//errors in ms/mono since we skip the other slot
|
||||||
// cach_err = dmr_cach (opts, state, cachdata);
|
// cach_err = dmr_cach (opts, state, cachdata);
|
||||||
@@ -354,7 +339,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
if (vc > 6) goto END;
|
if (vc > 6) goto END;
|
||||||
|
|
||||||
skipDibit (opts, state, 144); //skip to next tdma channel
|
skipDibit (opts, state, 144); //skip to next tdma channel
|
||||||
state->dmr_ms_rc = 0;
|
|
||||||
|
|
||||||
//since we are in a loop, run ncursesPrinter here
|
//since we are in a loop, run ncursesPrinter here
|
||||||
if (opts->use_ncurses_terminal == 1)
|
if (opts->use_ncurses_terminal == 1)
|
||||||
@@ -362,6 +346,10 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
ncursesPrinter(opts, state);
|
ncursesPrinter(opts, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//slot 1
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
} // end loop
|
} // end loop
|
||||||
|
|
||||||
END:
|
END:
|
||||||
@@ -382,15 +370,28 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
state->dmr_stereo = 0;
|
state->dmr_stereo = 0;
|
||||||
state->dmr_ms_mode = 0;
|
state->dmr_ms_mode = 0;
|
||||||
state->dmr_ms_rc = 0;
|
|
||||||
state->directmode = 0; //flag off
|
state->directmode = 0; //flag off
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset static ks counter
|
||||||
|
state->static_ks_counter[0] = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//collect buffered 1st half and get 2nd half voice payload and then jump to full MS Voice decoding.
|
//collect buffered 1st half and get 2nd half voice payload and then jump to full MS Voice decoding.
|
||||||
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * timestr = getTimeC();
|
||||||
|
|
||||||
|
//reset static ks counter
|
||||||
|
state->static_ks_counter[0] = 0;
|
||||||
|
|
||||||
int i, dibit;
|
int i, dibit;
|
||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
|
|
||||||
@@ -414,22 +415,6 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
char cachdata[25];
|
char cachdata[25];
|
||||||
UNUSED(cachdata);
|
UNUSED(cachdata);
|
||||||
|
|
||||||
//add time to mirror sync
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->dmrburstL = 16;
|
state->dmrburstL = 16;
|
||||||
state->currentslot = 0; //force to slot 0
|
state->currentslot = 0; //force to slot 0
|
||||||
|
|
||||||
@@ -565,13 +550,15 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", getTime());
|
fprintf (stderr, "%s ", timestr);
|
||||||
if (opts->inverted_dmr == 0)
|
if (opts->inverted_dmr == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||||
}
|
}
|
||||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
||||||
|
if (state->dmr_color_code != 16)
|
||||||
|
fprintf (stderr, "| Color Code=%02d ", state->dmr_color_code);
|
||||||
|
else fprintf (stderr, "| Color Code=XX ");
|
||||||
fprintf (stderr, "| VC* ");
|
fprintf (stderr, "| VC* ");
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
@@ -587,37 +574,38 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||||
|
|
||||||
if (state->directmode == 0)
|
if (state->tyt_bp == 1)
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
tyt16_ambe2_codeword_keystream(state, ambe_fr, 0);
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
tyt16_ambe2_codeword_keystream(state, ambe_fr2, 1);
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
tyt16_ambe2_codeword_keystream(state, ambe_fr3, 0);
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
|
|
||||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
|
||||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
|
||||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
|
||||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
|
||||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->csi_ee == 1)
|
||||||
|
{
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr2);
|
||||||
|
csi72_ambe2_codeword_keystream(state, ambe_fr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PRINT_AMBE72
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr2);
|
||||||
|
ambe2_codeword_print_i(opts, ambe_fr3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||||
|
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||||
|
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||||
|
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||||
|
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||||
|
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||||
|
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
||||||
|
|
||||||
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
||||||
if (opts->floating_point == 0)
|
if (opts->floating_point == 0)
|
||||||
@@ -635,10 +623,16 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//collect the mi fragment
|
//collect the mi fragment
|
||||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
if (opts->dmr_le != 2) //if not Hytera Enhanced
|
||||||
|
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||||
|
|
||||||
//errors due to skipping other slot
|
//errors due to skipping other slot
|
||||||
// cach_err = dmr_cach (opts, state, cachdata);
|
// cach_err = dmr_cach (opts, state, cachdata);
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
skipDibit (opts, state, 144); //skip to next TDMA slot
|
skipDibit (opts, state, 144); //skip to next TDMA slot
|
||||||
dmrMS (opts, state); //bootstrap into full TDMA frame
|
dmrMS (opts, state); //bootstrap into full TDMA frame
|
||||||
@@ -648,27 +642,13 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
|||||||
//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing
|
//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing
|
||||||
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * timestr = getTimeC();
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int dibit;
|
int dibit;
|
||||||
int *dibit_p;
|
int *dibit_p;
|
||||||
|
|
||||||
//add time to mirror sync
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
||||||
dibit_p = state->dmr_payload_p - 90;
|
dibit_p = state->dmr_payload_p - 90;
|
||||||
for (i = 0; i < 90; i++) //90
|
for (i = 0; i < 90; i++) //90
|
||||||
@@ -677,7 +657,6 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
|||||||
dibit_p++;
|
dibit_p++;
|
||||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||||
state->dmr_stereo_payload[i] = dibit;
|
state->dmr_stereo_payload[i] = dibit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 54; i++)
|
for (i = 0; i < 54; i++)
|
||||||
@@ -685,16 +664,17 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
|||||||
dibit = getDibit(opts, state);
|
dibit = getDibit(opts, state);
|
||||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||||
state->dmr_stereo_payload[i+90] = dibit;
|
state->dmr_stereo_payload[i+90] = dibit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "%s ", getTime());
|
fprintf (stderr, "%s ", timestr);
|
||||||
if (opts->inverted_dmr == 0)
|
if (opts->inverted_dmr == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||||
}
|
}
|
||||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
||||||
|
if (state->dmr_color_code != 16)
|
||||||
|
fprintf (stderr, "| Color Code=%02d ", state->dmr_color_code);
|
||||||
|
else fprintf (stderr, "| Color Code=XX ");
|
||||||
|
|
||||||
sprintf(state->slot1light, "%s", "");
|
sprintf(state->slot1light, "%s", "");
|
||||||
sprintf(state->slot2light, "%s", "");
|
sprintf(state->slot2light, "%s", "");
|
||||||
@@ -710,16 +690,23 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
|||||||
state->directmode = 0; //flag off
|
state->directmode = 0; //flag off
|
||||||
|
|
||||||
//should just be loaded in the dmr_payload_buffer instead now
|
//should just be loaded in the dmr_payload_buffer instead now
|
||||||
|
//but we want to run getDibit so the buffer has actual good values in it
|
||||||
for (i = 0; i < 144; i++) //66
|
for (i = 0; i < 144; i++) //66
|
||||||
{
|
{
|
||||||
dibit = getDibit(opts, state);
|
dibit = getDibit(opts, state);
|
||||||
state->dmr_stereo_payload[i] = dibit;
|
state->dmr_stereo_payload[i] = 1; //set to one so first frame will fail intentionally instead of zero fill
|
||||||
}
|
}
|
||||||
//CACH + First Half Payload = 12 + 54
|
//CACH + First Half Payload = 12 + 54
|
||||||
for (i = 0; i < 66; i++) //66
|
for (i = 0; i < 66; i++) //66
|
||||||
{
|
{
|
||||||
dibit = getDibit(opts, state);
|
dibit = getDibit(opts, state);
|
||||||
state->dmr_stereo_payload[i] = dibit;
|
state->dmr_stereo_payload[i+66] = 1; ////set to one so first frame will fail intentionally instead of zero fill
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
952
src/dmr_pdu.c
952
src/dmr_pdu.c
File diff suppressed because it is too large
Load Diff
558
src/dmr_pi.c
558
src/dmr_pi.c
@@ -12,87 +12,278 @@
|
|||||||
|
|
||||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||||
{
|
{
|
||||||
UNUSED2(opts, CRCCorrect);
|
|
||||||
|
|
||||||
if((IrrecoverableErrors == 0))
|
uint8_t MFID = PI_BYTE[1];
|
||||||
|
|
||||||
|
if(IrrecoverableErrors == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||||
|
if (opts->p25_is_tuned == 1)
|
||||||
{
|
{
|
||||||
state->payload_algid = PI_BYTE[0];
|
state->last_vc_sync_time = time(NULL);
|
||||||
state->payload_keyid = PI_BYTE[2];
|
state->last_cc_sync_time = time(NULL);
|
||||||
state->payload_mi = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
|
|
||||||
if (state->payload_algid < 0x26)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s ", KYEL);
|
|
||||||
fprintf (stderr, "\n Slot 1");
|
|
||||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
|
||||||
|
|
||||||
//Anytone RC4 Shim
|
|
||||||
if (state->payload_algid == 0x01)
|
|
||||||
{
|
|
||||||
fprintf (stderr, " Anytone (0x01)");
|
|
||||||
state->payload_algid = 0x21;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "%s ", KNRM);
|
|
||||||
if (state->payload_algid != 0x21)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
LFSR64 (state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->payload_algid >= 0x26)
|
|
||||||
{
|
|
||||||
state->payload_algid = 0;
|
|
||||||
state->payload_keyid = 0;
|
|
||||||
state->payload_mi = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->currentslot == 1)
|
if (MFID == 0x0A && CRCCorrect == 1) //Kirisun
|
||||||
{
|
{
|
||||||
|
uint8_t so = PI_BYTE[2]; //in VLC and PI, this byte is 0x40, so thinking this could be SVC_OPT
|
||||||
|
uint8_t alg = PI_BYTE[0]; //observed 0x36 and 0x37 for Kirisun Advanced and Universal Privacy
|
||||||
|
// uint8_t kid = PI_BYTE[2]; //user info conveyed there is only 16 allotments for Key, and keys are channel specific, so no key id value
|
||||||
|
uint32_t target = ((unsigned long long int)PI_BYTE[7] << 16) | ((unsigned long long int)PI_BYTE[8] << 8) | ((unsigned long long int)PI_BYTE[9] << 0);
|
||||||
|
|
||||||
state->payload_algidR = PI_BYTE[0];
|
//TODO: Use ALG and TGT value here to produce a key id via hashing it
|
||||||
state->payload_keyidR = PI_BYTE[2];
|
uint8_t hash = alg * target % 256; //more complex hash later (honestly, probably not)
|
||||||
state->payload_miR = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
|
|
||||||
if (state->payload_algidR < 0x26)
|
//MI only appears to be 32-bit
|
||||||
|
uint32_t mi = ((uint32_t)PI_BYTE[3] << 24) | ((uint32_t)PI_BYTE[4] << 16) |
|
||||||
|
((uint32_t)PI_BYTE[5] << 8) | ((uint32_t)PI_BYTE[6] << 0);
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s ", KYEL);
|
state->dmr_so = so;
|
||||||
fprintf (stderr, "\n Slot 2");
|
state->payload_algid = alg;
|
||||||
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
state->payload_keyid = hash;
|
||||||
|
state->payload_mi = mi;
|
||||||
//Anytone RC4 Shim
|
}
|
||||||
if (state->payload_algidR == 0x01)
|
else
|
||||||
{
|
{
|
||||||
fprintf (stderr, " Anytone (0x01)");
|
state->dmr_soR = so;
|
||||||
state->payload_algidR = 0x21;
|
state->payload_algidR = alg;
|
||||||
}
|
state->payload_keyidR = hash;
|
||||||
|
state->payload_miR = mi;
|
||||||
fprintf (stderr, "%s ", KNRM);
|
|
||||||
if (state->payload_algidR != 0x21)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
LFSR64 (state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->payload_algidR >= 0x26)
|
fprintf (stderr, "%s ", KYEL);
|
||||||
{
|
fprintf (stderr, "\n Slot %d", state->currentslot+1);
|
||||||
state->payload_algidR = 0;
|
fprintf (stderr, " DMR PI H- ALG ID: %02X; KEY ID: %02X; MI(32): %08X;", alg, hash, mi);
|
||||||
state->payload_keyidR = 0;
|
|
||||||
state->payload_miR = 0;
|
fprintf (stderr, " Kirisun ");
|
||||||
}
|
if (alg == 0x36)
|
||||||
|
fprintf (stderr, "Advanced;");
|
||||||
|
else if (alg == 0x37)
|
||||||
|
fprintf (stderr, "Universal;");
|
||||||
|
else fprintf (stderr, "Encryption;");
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
|
//disable late entry for DMRA, Flag 3 for future check of VC-F 48-bit region with Golay 24,12 Encoding
|
||||||
|
//SEE: https://patents.google.com/patent/CN102307075A/en?q=(kirisun)&q=(dmr)&oq=kirisun
|
||||||
|
//tested patent above with information provided, VC-F had a SB, but the 48-bit
|
||||||
|
//full value yielded bad Golay results, and user submitted info contradicts this patent for samples provided
|
||||||
|
//Late Entry MI does appear to work, however, and reports a good CRC for that as well,
|
||||||
|
//reverse engineered LFSR for Kirisun lines up with the late entry for 32-bit MI values.
|
||||||
|
opts->dmr_le = 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MFID == 0x68) //Hytera Enhanced
|
||||||
|
{
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
state->dmr_so |= 0x40; //OR the enc bit onto the SO
|
||||||
|
state->payload_algid = PI_BYTE[0];
|
||||||
|
state->payload_keyid = PI_BYTE[2];
|
||||||
|
state->payload_mi = ((unsigned long long int)PI_BYTE[3] << 32ULL) | ((unsigned long long int)PI_BYTE[4] << 24) |
|
||||||
|
((unsigned long long int)PI_BYTE[5] << 16) | ((unsigned long long int)PI_BYTE[6] << 8) | ((unsigned long long int)PI_BYTE[7] << 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state->dmr_soR |= 0x40; //OR the enc bit onto the SO
|
||||||
|
state->payload_algidR = PI_BYTE[0];
|
||||||
|
state->payload_keyidR = PI_BYTE[2];
|
||||||
|
state->payload_miR = ((unsigned long long int)PI_BYTE[3] << 32ULL) | ((unsigned long long int)PI_BYTE[4] << 24) |
|
||||||
|
((unsigned long long int)PI_BYTE[5] << 16) | ((unsigned long long int)PI_BYTE[6] << 8) | ((unsigned long long int)PI_BYTE[7] << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "%s ", KYEL);
|
||||||
|
fprintf (stderr, "\n Slot %d", state->currentslot+1);
|
||||||
|
fprintf (stderr, " DMR PI H- ALG ID: %02X; KEY ID: %02X; MI(40): %02X%02X%02X%02X%02X;",
|
||||||
|
PI_BYTE[0], PI_BYTE[2], PI_BYTE[3], PI_BYTE[4], PI_BYTE[5], PI_BYTE[6], PI_BYTE[7]);
|
||||||
|
|
||||||
|
//PI_BYTE[9] is a checksum of the other bytes combined
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (int i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
checksum += PI_BYTE[i];
|
||||||
|
checksum &= 0xFF;
|
||||||
|
}
|
||||||
|
checksum = ~checksum & 0xFF;
|
||||||
|
checksum++;
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " CHK: %02X / %02X;", checksum, PI_BYTE[9]);
|
||||||
|
|
||||||
|
if (checksum == PI_BYTE[9])
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Hytera Enhanced; ");
|
||||||
|
|
||||||
|
if (state->currentslot == 0 && state->R != 0)
|
||||||
|
fprintf (stderr, "Key: %010llX; ", state->R);
|
||||||
|
|
||||||
|
if (state->currentslot == 1 && state->RR != 0)
|
||||||
|
fprintf (stderr, "Key: %010llX; ", state->RR);
|
||||||
|
|
||||||
|
//disable late entry for DMRA (hopefully, there aren't any systems running both DMRA and Hytera Enhanced mixed together)
|
||||||
|
opts->dmr_le = 2;
|
||||||
|
|
||||||
|
// fprintf (stderr, " (Checksum Okay);");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KRED);
|
||||||
|
fprintf (stderr, " (Checksum Err);");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (MFID == 0x10) //DMRA
|
||||||
|
{
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
state->payload_algid = PI_BYTE[0];
|
||||||
|
state->payload_keyid = PI_BYTE[2];
|
||||||
|
state->payload_mi = ((unsigned long long int)PI_BYTE[3] << 24ULL) | ((unsigned long long int)PI_BYTE[4] << 16ULL) | ((unsigned long long int)PI_BYTE[5] << 8ULL) | ((unsigned long long int)PI_BYTE[6] << 0ULL);
|
||||||
|
if (state->payload_algid < 0x26)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s ", KYEL);
|
||||||
|
fprintf (stderr, "\n Slot 1");
|
||||||
|
fprintf (stderr, " DMR PI H- ALG ID: %02X; KEY ID: %02X; MI(32): %08llX;", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||||
|
|
||||||
|
//check for any values that aren't 0x2X but just 0x0X
|
||||||
|
//going to be very generic here to avoid any particular vendors using 0x2X and not 0x0X
|
||||||
|
if (state->payload_algid & 0x20)
|
||||||
|
fprintf (stderr, " DMRA");
|
||||||
|
else fprintf (stderr, " DMRA Compatible");
|
||||||
|
|
||||||
|
if ((state->payload_algid & 0x07) == 0x01)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " RC4;");
|
||||||
|
state->payload_algid = 0x21;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algid & 0x07) == 0x02)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " DES;");
|
||||||
|
state->payload_algid = 0x22;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algid & 0x07) == 0x04)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AES-128;");
|
||||||
|
state->payload_algid = 0x24;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algid & 0x07) == 0x05)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AES-256;");
|
||||||
|
state->payload_algid = 0x25;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
|
||||||
|
//expand the 32-bit MI to a 64-bit DES IV
|
||||||
|
if (state->payload_algid == 0x22)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
LFSR64 (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
//expand the 32-bit MI to a 128-bit AES IV
|
||||||
|
if (state->payload_algid == 0x24 || state->payload_algid == 0x25)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
LFSR128d (state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->payload_algid >= 0x26)
|
||||||
|
{
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->currentslot == 1)
|
||||||
|
{
|
||||||
|
|
||||||
|
state->payload_algidR = PI_BYTE[0];
|
||||||
|
state->payload_keyidR = PI_BYTE[2];
|
||||||
|
state->payload_miR = ((unsigned long long int)PI_BYTE[3] << 24ULL) | ((unsigned long long int)PI_BYTE[4] << 16ULL) | ((unsigned long long int)PI_BYTE[5] << 8ULL) | ((unsigned long long int)PI_BYTE[6] << 0ULL);
|
||||||
|
if (state->payload_algidR < 0x26)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s ", KYEL);
|
||||||
|
fprintf (stderr, "\n Slot 2");
|
||||||
|
fprintf (stderr, " DMR PI H- ALG ID: %02X; KEY ID: %02X; MI(32): %08llX;", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||||||
|
|
||||||
|
//check for any values that aren't 0x2X but just 0x0X
|
||||||
|
//going to be very generic here to avoid any particular vendors using 0x2X and not 0x0X
|
||||||
|
if (state->payload_algidR & 0x20)
|
||||||
|
fprintf (stderr, " DMRA");
|
||||||
|
else fprintf (stderr, " DMRA Compatible");
|
||||||
|
|
||||||
|
if ((state->payload_algidR & 0x07) == 0x01)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " RC4;");
|
||||||
|
state->payload_algidR = 0x21;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algidR & 0x07) == 0x02)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " DES;");
|
||||||
|
state->payload_algidR = 0x22;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algidR & 0x07) == 0x04)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AES-128;");
|
||||||
|
state->payload_algidR = 0x24;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((state->payload_algidR & 0x07) == 0x05)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " AES-256;");
|
||||||
|
state->payload_algidR = 0x25;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fprintf (stderr, "%s ", KNRM);
|
||||||
|
|
||||||
|
//expand the 32-bit MI to a 64-bit DES IV
|
||||||
|
if (state->payload_algidR == 0x22)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
LFSR64 (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
//expand the 32-bit MI to a 128-bit AES IV
|
||||||
|
if (state->payload_algidR == 0x24 || state->payload_algidR == 0x25)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
LFSR128d (state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->payload_algidR >= 0x26)
|
||||||
|
{
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} //end DMRA
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFSR(dsd_state * state)
|
void LFSR(dsd_state * state)
|
||||||
{
|
{
|
||||||
int lfsr = 0;
|
unsigned long long int lfsr = 0;
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
lfsr = state->payload_mi;
|
lfsr = state->payload_mi;
|
||||||
@@ -104,16 +295,19 @@ void LFSR(dsd_state * state)
|
|||||||
for(cnt=0;cnt<32;cnt++)
|
for(cnt=0;cnt<32;cnt++)
|
||||||
{
|
{
|
||||||
// Polynomial is C(x) = x^32 + x^4 + x^2 + 1
|
// Polynomial is C(x) = x^32 + x^4 + x^2 + 1
|
||||||
int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1;
|
unsigned long long int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1;
|
||||||
lfsr = (lfsr << 1) | (bit);
|
lfsr = (lfsr << 1) | bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lfsr &= 0xFFFFFFFF;
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
||||||
fprintf(stderr, " MI: 0x%08X", lfsr);
|
fprintf (stderr, " MI(32): %08llX;", lfsr);
|
||||||
|
fprintf (stderr, " RC4;");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
state->payload_mi = lfsr;
|
state->payload_mi = lfsr;
|
||||||
}
|
}
|
||||||
@@ -123,51 +317,241 @@ void LFSR(dsd_state * state)
|
|||||||
|
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
||||||
fprintf(stderr, " MI: 0x%08X", lfsr);
|
fprintf(stderr, " MI(32): %08llX;", lfsr);
|
||||||
|
fprintf (stderr, " RC4;");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
state->payload_miR = lfsr;
|
state->payload_miR = lfsr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Expand a 32-bit MI into a 64-bit IV for DES
|
||||||
void LFSR64(dsd_state * state)
|
void LFSR64(dsd_state * state)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
unsigned long long int lfsr = 0;
|
unsigned long long int lfsr = 0;
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
lfsr = (uint64_t) state->payload_mi;
|
lfsr = (uint64_t) state->payload_mi;
|
||||||
}
|
}
|
||||||
else lfsr = (uint64_t) state->payload_miR;
|
else lfsr = (uint64_t) state->payload_miR;
|
||||||
|
|
||||||
uint8_t cnt = 0;
|
uint8_t cnt = 0;
|
||||||
|
|
||||||
for(cnt=0;cnt<32;cnt++)
|
for(cnt=0;cnt<32;cnt++)
|
||||||
{
|
{
|
||||||
unsigned long long int bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
unsigned long long int bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
||||||
lfsr = (lfsr << 1) | bit;
|
lfsr = (lfsr << 1) | bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->currentslot == 0)
|
if (state->currentslot == 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 1");
|
fprintf (stderr, " Slot 1");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algid, state->payload_keyid);
|
||||||
fprintf (stderr, " MI: 0x%016llX", lfsr);
|
fprintf (stderr, " MI(64): %016llX;", lfsr);
|
||||||
|
fprintf (stderr, " DES;");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
||||||
}
|
state->payload_miP = lfsr;
|
||||||
|
state->DMRvcL = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->currentslot == 1)
|
if (state->currentslot == 1)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s", KYEL);
|
fprintf (stderr, "%s", KYEL);
|
||||||
fprintf (stderr, " Slot 2");
|
fprintf (stderr, " Slot 2");
|
||||||
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X;", state->payload_algidR, state->payload_keyidR);
|
||||||
fprintf (stderr, " MI: 0x%016llX", lfsr);
|
fprintf (stderr, " MI(64): %016llX;", lfsr);
|
||||||
|
fprintf (stderr, " DES;");
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
|
||||||
}
|
state->payload_miN = lfsr;
|
||||||
|
state->DMRvcR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Expand a 32-bit MI into a 128-bit IV for AES
|
||||||
|
void LFSR128d(dsd_state * state)
|
||||||
|
{
|
||||||
|
unsigned long long int lfsr = 0;
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
lfsr = state->payload_mi;
|
||||||
|
else lfsr = state->payload_miR;
|
||||||
|
|
||||||
|
unsigned long long int next_mi;
|
||||||
|
|
||||||
|
//start packing aes_iv
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
state->aes_iv[0] = (lfsr >> 24) & 0xFF;
|
||||||
|
state->aes_iv[1] = (lfsr >> 16) & 0xFF;
|
||||||
|
state->aes_iv[2] = (lfsr >> 8 ) & 0xFF;
|
||||||
|
state->aes_iv[3] = (lfsr >> 0 ) & 0xFF;
|
||||||
|
}
|
||||||
|
else if (state->currentslot == 1)
|
||||||
|
{
|
||||||
|
state->aes_ivR[0] = (lfsr >> 24) & 0xFF;
|
||||||
|
state->aes_ivR[1] = (lfsr >> 16) & 0xFF;
|
||||||
|
state->aes_ivR[2] = (lfsr >> 8 ) & 0xFF;
|
||||||
|
state->aes_ivR[3] = (lfsr >> 0 ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = 0; int x = 32;
|
||||||
|
unsigned long long int bit;
|
||||||
|
for(cnt=0;cnt<96;cnt++)
|
||||||
|
{
|
||||||
|
//32,22,2,1
|
||||||
|
bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
|
||||||
|
lfsr = (lfsr << 1) | bit;
|
||||||
|
|
||||||
|
//continue packing aes_iv
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
state->aes_iv[x/8] = (state->aes_iv[x/8] << 1) + bit;
|
||||||
|
else if (state->currentslot == 1)
|
||||||
|
state->aes_ivR[x/8] = (state->aes_ivR[x/8] << 1) + bit;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//assign the next 32-bit short MI from 4,5,6,7 so it'll match up with OTA late entry
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
next_mi = ((unsigned long long int)state->aes_iv[4] << 24) | ((unsigned long long int)state->aes_iv[5] << 16) |
|
||||||
|
((unsigned long long int)state->aes_iv[6] << 8) | ((unsigned long long int)state->aes_iv[7] << 0);
|
||||||
|
if (state->currentslot == 1)
|
||||||
|
next_mi = ((unsigned long long int)state->aes_ivR[4] << 24) | ((unsigned long long int)state->aes_ivR[5] << 16) |
|
||||||
|
((unsigned long long int)state->aes_ivR[6] << 8) | ((unsigned long long int)state->aes_ivR[7] << 0);
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 1");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X; MI(128): ", state->payload_algid, state->payload_keyid);
|
||||||
|
for (x = 0; x < 16; x++)
|
||||||
|
fprintf (stderr, "%02X", state->aes_iv[x]);
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
fprintf (stderr, ";");
|
||||||
|
|
||||||
|
if (state->payload_algid == 0x24)
|
||||||
|
fprintf (stderr, " AES-128;");
|
||||||
|
else fprintf (stderr, " AES-256;");
|
||||||
|
|
||||||
|
state->payload_mi = next_mi;
|
||||||
|
state->DMRvcL = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->currentslot == 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s", KYEL);
|
||||||
|
fprintf (stderr, " Slot 2");
|
||||||
|
fprintf (stderr, " DMR PI C- ALG ID: %02X; KEY ID: %02X; MI(128): ", state->payload_algidR, state->payload_keyidR);
|
||||||
|
for (x = 0; x < 16; x++)
|
||||||
|
fprintf (stderr, "%02X", state->aes_ivR[x]);
|
||||||
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
fprintf (stderr, ";");
|
||||||
|
|
||||||
|
if (state->payload_algidR == 0x24)
|
||||||
|
fprintf (stderr, " AES-128;");
|
||||||
|
else fprintf (stderr, " AES-256;");
|
||||||
|
|
||||||
|
state->payload_miR = next_mi;
|
||||||
|
state->DMRvcR = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long int hytera_lfsr(uint8_t * mi, uint8_t * taps, uint8_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
uint8_t bit = (mi[i] >> 7) & 1;
|
||||||
|
mi[i] <<= 1;
|
||||||
|
if (bit) mi[i] ^= taps[i%len];
|
||||||
|
mi[i] |= bit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long int mi_value = 0;
|
||||||
|
for (uint8_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
mi_value <<= 8;
|
||||||
|
mi_value |= mi[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " Next MI: %010llX \n", mi_value);
|
||||||
|
|
||||||
|
return mi_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hytera_enhanced_alg_refresh(dsd_state * state)
|
||||||
|
{
|
||||||
|
uint8_t mi[5]; memset (mi, 0, sizeof(mi));
|
||||||
|
unsigned long long int mi_value = 0;
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
mi_value = state->payload_mi;
|
||||||
|
else mi_value = state->payload_miR;
|
||||||
|
|
||||||
|
//load mi_value into mi array
|
||||||
|
mi[0] = ((mi_value & 0xFF00000000) >> 32UL);
|
||||||
|
mi[1] = ((mi_value & 0xFF000000) >> 24);
|
||||||
|
mi[2] = ((mi_value & 0xFF0000) >> 16);
|
||||||
|
mi[3] = ((mi_value & 0xFF00) >> 8);
|
||||||
|
mi[4] = ((mi_value & 0xFF) >> 0);
|
||||||
|
|
||||||
|
//calculate the next MI value
|
||||||
|
uint8_t taps[5]; memset(taps, 0, sizeof(taps));
|
||||||
|
|
||||||
|
//the tap values
|
||||||
|
taps[0] = 0x12;
|
||||||
|
taps[1] = 0x24;
|
||||||
|
taps[2] = 0x48;
|
||||||
|
taps[3] = 0x22;
|
||||||
|
taps[4] = 0x14;
|
||||||
|
mi_value = hytera_lfsr(mi, taps, 5);
|
||||||
|
|
||||||
|
if (state->currentslot == 0)
|
||||||
|
state->payload_mi = mi_value;
|
||||||
|
else state->payload_miR = mi_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t kirisun_lfsr(unsigned long long int mi)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t taps = 0xD459C4F1;
|
||||||
|
uint32_t lfsr = (uint32_t)mi;
|
||||||
|
uint32_t new_mi = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t byte = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
uint32_t temp = (lfsr << 1);
|
||||||
|
uint8_t msb = (lfsr >> 31) & 1;
|
||||||
|
|
||||||
|
if (msb)
|
||||||
|
{
|
||||||
|
byte |= (1 << j);
|
||||||
|
lfsr = temp ^ taps;
|
||||||
|
}
|
||||||
|
else lfsr = temp; //was previously temp ^ 1, but that isn't a primitive
|
||||||
|
}
|
||||||
|
|
||||||
|
new_mi <<=8;
|
||||||
|
new_mi |= byte;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_mi;
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
//modified to accept variable payload size and len
|
//modified to accept variable payload size and len
|
||||||
uint16_t ComputeCrcCCITT16d(const uint8_t buf[], uint8_t len)
|
uint16_t ComputeCrcCCITT16d(const uint8_t * buf, uint32_t len)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
|
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
//check other as well before assigning
|
//check other as well before assigning
|
||||||
if(state->dPMRVoiceFS2Frame.CallingIDOk) sprintf (state->dpmr_target_id, "%s", CalledID);
|
if(state->dPMRVoiceFS2Frame.CalledIDOk) sprintf (state->dpmr_target_id, "%s", CalledID);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -473,12 +473,16 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
|||||||
//flag back off if key is provided
|
//flag back off if key is provided
|
||||||
if (state->R != 0) state->dmr_encL = 0;
|
if (state->R != 0) state->dmr_encL = 0;
|
||||||
|
|
||||||
|
//print Current Frame Number if payload verbosity enabled
|
||||||
|
if (opts->payload == 1)
|
||||||
|
fprintf (stderr, "\n FN %d/4", state->dPMRVoiceFS2Frame.FrameNumbering[o]+1);
|
||||||
|
|
||||||
//There are 4 AMBE voice frames per TCH
|
//There are 4 AMBE voice frames per TCH
|
||||||
for(i = start; i < end; i++)
|
for(i = start; i < end; i++)
|
||||||
{
|
{
|
||||||
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
||||||
if (opts->floating_point == 0)
|
if (opts->floating_point == 0)
|
||||||
playSynthesizedVoice(opts, state);
|
playSynthesizedVoiceMS(opts, state);
|
||||||
if (opts->floating_point == 1)
|
if (opts->floating_point == 1)
|
||||||
playSynthesizedVoiceFM(opts, state);
|
playSynthesizedVoiceFM(opts, state);
|
||||||
}
|
}
|
||||||
|
|||||||
825
src/dsd_alias.c
Normal file
825
src/dsd_alias.c
Normal file
@@ -0,0 +1,825 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dsd_alias.c
|
||||||
|
* Talker Alias Handling for Various Protocols and Vendors
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2025-02 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
//Motorola P25 OTA Alias Decoding ripped/demystified from Ilya Smirnov's SDRTrunk Voodoo Code
|
||||||
|
uint8_t moto_alias_lut[256] = {
|
||||||
|
0xD2, 0xF6, 0xD4, 0x2B, 0x63, 0x49, 0x94, 0x5E, 0xA7, 0x5C, 0x70, 0x69, 0xF7, 0x08, 0xB1, 0x7D,
|
||||||
|
0x38, 0xCF, 0xCC, 0xD8, 0x51, 0x8F, 0xD5, 0x93, 0x6A, 0xF3, 0xEF, 0x7E, 0xFB, 0x64, 0xF4, 0x35,
|
||||||
|
0x27, 0x07, 0x31, 0x14, 0x87, 0x98, 0x76, 0x34, 0xCA, 0x92, 0x33, 0x1B, 0x4F, 0x8C, 0x09, 0x40,
|
||||||
|
0x32, 0x36, 0x77, 0x12, 0xD3, 0xC3, 0x01, 0xAB, 0x72, 0x81, 0x95, 0xC9, 0xC0, 0xE9, 0x65, 0x52,
|
||||||
|
0x24, 0x30, 0x1C, 0xDB, 0x88, 0xE8, 0x97, 0x9D, 0x58, 0x26, 0x04, 0x39, 0xAC, 0x2A, 0x9E, 0xAA,
|
||||||
|
0x25, 0xD7, 0xCE, 0xEB, 0x96, 0xF5, 0x0E, 0x8D, 0xDC, 0xA9, 0x2F, 0xDD, 0x1F, 0xEA, 0x91, 0xB7,
|
||||||
|
0xD6, 0x89, 0x8B, 0xD1, 0xB0, 0x99, 0x13, 0x7A, 0xE7, 0x9A, 0xB5, 0x86, 0xFF, 0x46, 0x85, 0xB2,
|
||||||
|
0x73, 0xDA, 0xBF, 0xD0, 0x71, 0xCB, 0x4D, 0x80, 0x15, 0x67, 0x16, 0x1A, 0x20, 0x8E, 0x45, 0x3E,
|
||||||
|
0xF2, 0x2E, 0x66, 0x90, 0x74, 0x8A, 0x6F, 0x78, 0xBB, 0x53, 0x03, 0x11, 0x68, 0xCD, 0x44, 0x17,
|
||||||
|
0x28, 0x5F, 0x1E, 0x84, 0x75, 0x79, 0x6E, 0x9B, 0x2C, 0xBE, 0x62, 0x2D, 0xF1, 0x7C, 0xB8, 0x83,
|
||||||
|
0xD9, 0x4E, 0x6D, 0x02, 0x61, 0x3D, 0xA8, 0x06, 0xB9, 0xF8, 0x9C, 0x37, 0x3A, 0x23, 0xC1, 0x50,
|
||||||
|
0xED, 0x9F, 0xAF, 0x3B, 0xBD, 0x82, 0xBA, 0xA0, 0xDF, 0xC2, 0x47, 0x22, 0xF0, 0xEE, 0xA1, 0xFE,
|
||||||
|
0xA2, 0x10, 0x5B, 0x48, 0x57, 0xA3, 0x05, 0x60, 0x7B, 0x0D, 0xF9, 0x6C, 0xB3, 0x56, 0x4C, 0xBC,
|
||||||
|
0x29, 0xA4, 0x0F, 0xEC, 0xB6, 0xA5, 0xA6, 0x3C, 0x7F, 0x6B, 0xB4, 0x21, 0xAD, 0xAE, 0xC4, 0xC8,
|
||||||
|
0xC5, 0x5D, 0xDE, 0xE0, 0x1D, 0x19, 0x4B, 0xC6, 0x0C, 0x3F, 0x5A, 0xC7, 0xE1, 0x59, 0x55, 0x54,
|
||||||
|
0x4A, 0x43, 0x42, 0xE2, 0xE3, 0xFA, 0x00, 0xE4, 0xE5, 0x18, 0x41, 0x0B, 0x0A, 0xE6, 0xFC, 0xFD
|
||||||
|
};
|
||||||
|
|
||||||
|
void apx_embedded_alias_test_phase1 (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t temp_a = 0x15902D2806010005; uint64_t temp_b = 0xDE; //72 bits, so break into segments
|
||||||
|
uint8_t lcw[72]; memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x1790010BEE0740F0; temp_b = 0x4E;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x17900200DD2D2168; temp_b = 0x1A;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x17900301B52FFBFB; temp_b = 0xFE;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x1790040E53FE86BE; temp_b = 0xF7;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x17900508FD5AB910; temp_b = 0xB2;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x1790060376F9D800; temp_b = 0x00;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
//Harris Phase 1 GPS
|
||||||
|
state->lastsrc = 1000;
|
||||||
|
temp_a = 0x2AA41D4C24262328; temp_b = 0xAF;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
|
||||||
|
temp_a = 0x2BA44E0DB2660108; temp_b = 0x14;
|
||||||
|
memset (lcw, 0, sizeof(lcw));
|
||||||
|
for (uint64_t i = 0; i < 64; i++)
|
||||||
|
lcw[i] = (temp_a >> (63-i)) & 1;
|
||||||
|
for (uint64_t i = 0; i < 8; i++)
|
||||||
|
lcw[i+64] = (temp_b >> (7-i)) & 1;
|
||||||
|
p25_lcw(opts, state, lcw, 0);
|
||||||
|
state->lastsrc = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_header_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[32], 8); //len in blocks of associated talker alias
|
||||||
|
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[56], 4);
|
||||||
|
fprintf (stderr, " SN: %X;", sn);
|
||||||
|
fprintf (stderr, " BN: 0/%d;", ta_len);
|
||||||
|
|
||||||
|
//use dmr_pdu_sf for storage, store entire header (will be used to verify complete reception of full alias)
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot])); //reset storage for header and blocks
|
||||||
|
memcpy (state->dmr_pdu_sf[slot], lc_bits, 72*sizeof(uint8_t));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //current block number
|
||||||
|
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //is a static value on all block sequences
|
||||||
|
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][32], 8); //len in blocks pulled from stored header
|
||||||
|
uint16_t header = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0], 16); //header check, should be 0x1590
|
||||||
|
|
||||||
|
if (ta_len == 0 || header != 0x1590) //checkdown, make sure we have an up to date header for this with a good len value
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Missing Header");
|
||||||
|
fprintf (stderr, " BN: %d/??;", bn);
|
||||||
|
fprintf (stderr, " SN: %X;", sn);
|
||||||
|
fprintf (stderr, " Partial: ");
|
||||||
|
for (uint8_t i = 7; i < 18; i++)
|
||||||
|
fprintf (stderr, "%0X", (uint8_t)ConvertBitIntoBytes(&lc_bits[0+(i*4)], 4));
|
||||||
|
|
||||||
|
//clear out now stale storage
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot]));
|
||||||
|
}
|
||||||
|
|
||||||
|
else //good len and header stored
|
||||||
|
{
|
||||||
|
|
||||||
|
//sanity check, bn cannot equal zero (this shouldn't happen, but bad decode could occur)
|
||||||
|
if (bn == 0) bn = 1;
|
||||||
|
|
||||||
|
fprintf (stderr, " SN: %X;", sn);
|
||||||
|
fprintf (stderr, " BN: %d/%d;", bn, ta_len);
|
||||||
|
|
||||||
|
//use dmr_pdu_sf for storage, store data relevant portion at ptr of (bn-1) * 44 + 72 offset for header
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+(((bn-1)*44)+72), lc_bits+28, 44*sizeof(uint8_t));
|
||||||
|
|
||||||
|
if (ta_len == bn) //this is the last block, proceed to decoding
|
||||||
|
{
|
||||||
|
|
||||||
|
//Calculate variable len bits determined by non-zero octets
|
||||||
|
int16_t num_bits = 56; //starting value is the static bit count on the fqsuid
|
||||||
|
|
||||||
|
// //evaluate the storage and determine how many octets/bits are present at this point (fall back to this if needed)
|
||||||
|
// for (int16_t i = 0; i < 368; i++) //(3072-128)/8
|
||||||
|
// {
|
||||||
|
// uint8_t byte = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*8)], 8);
|
||||||
|
// if (byte == 0)
|
||||||
|
// break;
|
||||||
|
// else
|
||||||
|
// num_bits += 8;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//evaluate the storage and determine how many octets/bits are present at this point (expanded to two octets each, CRC with a 00xx pattern failed this)
|
||||||
|
for (int16_t i = 0; i < 184; i++) //(3072-128)/16
|
||||||
|
{
|
||||||
|
uint16_t bytes = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*16)], 16);
|
||||||
|
if (bytes == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
num_bits += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pass to alias decoder
|
||||||
|
apx_embedded_alias_decode (opts, state, slot, num_bits, state->dmr_pdu_sf[slot]);
|
||||||
|
|
||||||
|
//clear out now stale storage
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof(state->dmr_pdu_sf[slot]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_header_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[40], 8);
|
||||||
|
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[64], 4);
|
||||||
|
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[56], 8);
|
||||||
|
fprintf (stderr, " SN: %X;", sn); //NOTE: vPDU header is also a partial block, and has a block num and SN value in it
|
||||||
|
fprintf (stderr, " BN: %d/%d;", bn, ta_len);
|
||||||
|
|
||||||
|
//bit array to rearrange input lc_bits from phase 2 input to match the phase 1 header and block handling
|
||||||
|
uint8_t bits[136]; memset(bits, 0, sizeof(bits));
|
||||||
|
memcpy (bits, lc_bits, 2*8*sizeof(uint8_t)); //header 0x9190
|
||||||
|
memcpy (bits+16, lc_bits+24, 4*8*sizeof(uint8_t)); //BN, SN, etc
|
||||||
|
memcpy (bits+56, lc_bits+56, 10*8*sizeof(uint8_t)); //adding 8 bits of extra padding here
|
||||||
|
|
||||||
|
int16_t alias_st = 136; //start of the encoded alias (the copied size of this header, basically)
|
||||||
|
|
||||||
|
//debug, dump header arranged at this end
|
||||||
|
// fprintf (stderr, " Header: ");
|
||||||
|
// for (int16_t i = 0; i < alias_st/8; i++) //double check and adjust
|
||||||
|
// fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&bits[0+(i*8)], 8));
|
||||||
|
|
||||||
|
//use dmr_pdu_sf for storage, store entire header (will be used to verify complete reception of full alias)
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot])); //reset storage for header and blocks
|
||||||
|
memcpy (state->dmr_pdu_sf[slot], bits, alias_st*sizeof(uint8_t)); //this header block has 128 bits of relevant data (through the fqsuid)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_blocks_phase2 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
int16_t rel_bits = 100; //number of relevant bits in each block
|
||||||
|
int16_t rel_st = 36; //start of relevant bits in this block
|
||||||
|
int16_t alias_st = 136; //start of the encoded alias
|
||||||
|
uint8_t bn = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //current block number
|
||||||
|
uint8_t sn = (uint8_t)ConvertBitIntoBytes(&lc_bits[32], 4); //is a static value on all block sequences
|
||||||
|
uint8_t ta_len = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][32], 8); //len in blocks pulled from stored header
|
||||||
|
uint16_t header = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0], 16); //header check, should be 0x9190
|
||||||
|
|
||||||
|
if (ta_len == 0 || header != 0x9190)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " Missing Header");
|
||||||
|
fprintf (stderr, " BN: %d/??;", bn);
|
||||||
|
fprintf (stderr, " SN: %X;", sn);
|
||||||
|
fprintf (stderr, " Partial: ");
|
||||||
|
for (uint8_t i = 9; i < 32; i++) //double check and adjust
|
||||||
|
fprintf (stderr, "%0X", (uint8_t)ConvertBitIntoBytes(&lc_bits[0+(i*4)], 4));
|
||||||
|
|
||||||
|
//clear out now stale storage
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof(state->dmr_pdu_sf[slot]));
|
||||||
|
}
|
||||||
|
|
||||||
|
else //good len and header stored
|
||||||
|
{
|
||||||
|
|
||||||
|
//sanity check, bn cannot equal zero (this shouldn't happen, but bad decode could occur)
|
||||||
|
if (bn == 0) bn = 1;
|
||||||
|
|
||||||
|
fprintf (stderr, " SN: %X;", sn);
|
||||||
|
fprintf (stderr, " BN: %d/%d;", bn, ta_len);
|
||||||
|
|
||||||
|
//use dmr_pdu_sf for storage, store data relevant portion at ptr calculated below
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+(alias_st+((bn-1)*rel_bits)), lc_bits+rel_st, rel_bits*sizeof(uint8_t)); //Fix this value when samples arrive
|
||||||
|
|
||||||
|
//debug, dump accumulated data at this end
|
||||||
|
// fprintf (stderr, " Accumulated: ");
|
||||||
|
// for (int16_t i = 0; i < (alias_st+(rel_bits*bn))/8; i++) //double check and adjust
|
||||||
|
// fprintf (stderr, "%02X", (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][0+(i*8)], 8));
|
||||||
|
|
||||||
|
if (ta_len == bn) //this is the last block, proceed to decoding
|
||||||
|
{
|
||||||
|
|
||||||
|
//Calculate variable len bits determined by non-zero octets
|
||||||
|
int16_t num_bits = 56; //starting value is the static bit count on the fqsuid
|
||||||
|
|
||||||
|
// //evaluate the storage and determine how many octets/bits are present at this point (fall back to this if needed)
|
||||||
|
// for (int16_t i = 0; i < 368; i++) //(3072-128)/8
|
||||||
|
// {
|
||||||
|
// uint8_t byte = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*8)], 8);
|
||||||
|
// if (byte == 0)
|
||||||
|
// break;
|
||||||
|
// else
|
||||||
|
// num_bits += 8;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//evaluate the storage and determine how many octets/bits are present at this point (expanded to two octets each, CRC with a 00xx pattern failed this)
|
||||||
|
for (int16_t i = 0; i < 184; i++) //(3072-128)/16
|
||||||
|
{
|
||||||
|
uint16_t bytes = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][72+56+(i*16)], 16);
|
||||||
|
if (bytes == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
num_bits += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pass to alias decoder
|
||||||
|
apx_embedded_alias_decode (opts, state, slot, num_bits, state->dmr_pdu_sf[slot]);
|
||||||
|
|
||||||
|
//clear out now stale storage
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot]));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t num_bits, uint8_t * input)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(opts);
|
||||||
|
UNUSED(state);
|
||||||
|
UNUSED(slot);
|
||||||
|
|
||||||
|
//debug, dump completed data set
|
||||||
|
// fprintf (stderr, "\n Full: ");
|
||||||
|
// for (int16_t i = 0; i < (72+num_bits)/4; i++)
|
||||||
|
// fprintf (stderr, "%X", (uint8_t)ConvertBitIntoBytes(&input[0+(i*4)], 4));
|
||||||
|
|
||||||
|
//extract CRC
|
||||||
|
uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&input[(72+num_bits-16)], 16);
|
||||||
|
|
||||||
|
//compute CRC
|
||||||
|
uint16_t crc_cmp = ComputeCrcCCITT16d(&input[72], num_bits-16);
|
||||||
|
|
||||||
|
//print comparison
|
||||||
|
// fprintf (stderr, " CRC EXT: %04X CMP: %04X;", crc_ext, crc_cmp);
|
||||||
|
if (crc_ext != crc_cmp)
|
||||||
|
fprintf (stderr, " Alias CRC Error;");
|
||||||
|
// else fprintf (stderr, " Alias Okay;");
|
||||||
|
|
||||||
|
//start decoding the alias
|
||||||
|
if (crc_ext == crc_cmp)
|
||||||
|
{
|
||||||
|
|
||||||
|
//extract fully qualified SUID
|
||||||
|
uint32_t wacn = (uint32_t)ConvertBitIntoBytes(&input[72], 20);
|
||||||
|
uint32_t sys = (uint32_t)ConvertBitIntoBytes(&input[92], 12);
|
||||||
|
uint32_t rid = (uint32_t)ConvertBitIntoBytes(&input[104], 24);
|
||||||
|
|
||||||
|
//print fully qualified SUID
|
||||||
|
fprintf (stderr, "\n FQ-SUID: %05X.%03X.%06X (%d);", wacn, sys, rid, rid);
|
||||||
|
|
||||||
|
//WIP: Working, needs more samples to verify various num_bits values
|
||||||
|
uint16_t ptr = 128; //starting point of encoded alias
|
||||||
|
uint8_t encoded[200]; memset(encoded, 0, sizeof(encoded));
|
||||||
|
uint8_t decoded[200]; memset(decoded, 0, sizeof(decoded));
|
||||||
|
uint16_t num_bytes = (num_bits / 8) - 9; //subtract 2 CRC and 7 FQSUID
|
||||||
|
|
||||||
|
//sanity check
|
||||||
|
if (num_bytes <= 0) num_bytes = 1;
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < num_bytes; i++)
|
||||||
|
{
|
||||||
|
encoded[i] = (uint8_t)ConvertBitIntoBytes(&input[ptr], 8);
|
||||||
|
ptr += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t accumulator = num_bytes;
|
||||||
|
|
||||||
|
//Ilya's Voodoo Code
|
||||||
|
for (uint16_t i = 0; i < num_bytes; i++)
|
||||||
|
{
|
||||||
|
// Multiplication step 1
|
||||||
|
uint16_t accum_mult = accumulator * 293 + 0x72E9;
|
||||||
|
|
||||||
|
// Lookup table step
|
||||||
|
uint8_t lut = moto_alias_lut[encoded[i]];
|
||||||
|
uint8_t mult1 = lut - (accum_mult >> 8);
|
||||||
|
|
||||||
|
// Incrementing step
|
||||||
|
uint8_t mult2 = 1;
|
||||||
|
uint8_t shortstop = accum_mult | 0x1;
|
||||||
|
uint8_t increment = shortstop << 1;
|
||||||
|
|
||||||
|
//clang warning -- warning: result of comparison of constant -1 with expression of type 'uint8_t' (aka 'unsigned char') is always true [-Wtautological-constant-out-of-range-compare]
|
||||||
|
// while(mult2 != -1 && shortstop != 1) //clang warning can't be -1 if uint8_t (set to 255 instead?)
|
||||||
|
while(shortstop != 1) //this one tests out okay, so may use it instead
|
||||||
|
{
|
||||||
|
shortstop += increment;
|
||||||
|
mult2 += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplication step 2
|
||||||
|
decoded[i] = mult1 * mult2;
|
||||||
|
|
||||||
|
// Update the accumulator
|
||||||
|
accumulator += encoded[i] + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// //debug, dump just the encoded alias portion
|
||||||
|
// fprintf (stderr, "\n Encoded: ");
|
||||||
|
// for (int16_t i = 0; i < num_bytes; i++)
|
||||||
|
// fprintf (stderr, "%02X", encoded[i]);
|
||||||
|
|
||||||
|
// //debug, dump the decoded payload as hex octets
|
||||||
|
// fprintf (stderr, "\n Decoded: ");
|
||||||
|
// for (int16_t i = 0; i < num_bytes; i++)
|
||||||
|
// fprintf (stderr, "%02X", decoded[i]);
|
||||||
|
|
||||||
|
//dump the decoded payload as long chars
|
||||||
|
// fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, " Alias: ");
|
||||||
|
for (int16_t i = 0; i < num_bytes/2; i++)
|
||||||
|
fprintf (stderr, "%lc", ((decoded[(i*2)+0])<<8) | ((decoded[(i*2)+1])<<0) );
|
||||||
|
|
||||||
|
apx_embedded_alias_dump (opts, state, slot, num_bytes, input, decoded);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void apx_embedded_alias_dump (dsd_opts * opts, dsd_state * state, uint8_t slot, uint16_t num_bytes, uint8_t * input, uint8_t * decoded)
|
||||||
|
{
|
||||||
|
|
||||||
|
char str[50]; memset(str, 0, sizeof(str));
|
||||||
|
char fqs[50]; memset(fqs, 0, sizeof(fqs));
|
||||||
|
|
||||||
|
//check num_bytes, if greter than 100, then set to 100
|
||||||
|
if (num_bytes >= 98) num_bytes = 98;
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < num_bytes/2; i++)
|
||||||
|
{
|
||||||
|
if (decoded[(i*2)+1] == 0x2C) //remove a comma if it exists, change it to a 0x2E dot
|
||||||
|
str[i] = 0x2E;
|
||||||
|
else if (decoded[(i*2)+1] > 0x1F && decoded[(i*2)+1] < 0x7F) //may not need or use this restriction
|
||||||
|
str[i] = decoded[(i*2)+1];
|
||||||
|
else str[i] = 0x20; //space
|
||||||
|
}
|
||||||
|
|
||||||
|
//flag to indicate this already exists in import or group struct
|
||||||
|
uint8_t wr = 0;
|
||||||
|
|
||||||
|
//fully qualified SUID
|
||||||
|
uint32_t wacn = (uint32_t)ConvertBitIntoBytes(&input[72], 20);
|
||||||
|
uint32_t sys = (uint32_t)ConvertBitIntoBytes(&input[92], 12);
|
||||||
|
uint32_t rid = (uint32_t)ConvertBitIntoBytes(&input[104], 24);
|
||||||
|
|
||||||
|
sprintf (fqs, " FQ-SUID: %05X:%03X.%06X (%d);", wacn, sys, rid, rid);
|
||||||
|
if (rid != 0 && state->event_history_s[slot].Event_History_Items[0].source_id == rid)
|
||||||
|
{
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].alias, "%s; ", str);
|
||||||
|
strcat (state->event_history_s[slot].Event_History_Items[0].alias, fqs);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int16_t i = 0; i < state->group_tally; i++)
|
||||||
|
{
|
||||||
|
if (state->group_array[i].groupNumber == rid)
|
||||||
|
{
|
||||||
|
wr = 1; //already in there, so no need to assign it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wr == 0) //not already in there, so save it there now
|
||||||
|
{
|
||||||
|
state->group_array[state->group_tally].groupNumber = rid;
|
||||||
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
||||||
|
sprintf (state->group_array[state->group_tally].groupName, "%s", str);
|
||||||
|
state->group_tally++;
|
||||||
|
|
||||||
|
//if we have an opened group file, let's write what info we found into it
|
||||||
|
if (opts->group_in_file[0] != 0) //file is available
|
||||||
|
{
|
||||||
|
FILE * pFile; //file pointer
|
||||||
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
|
pFile = fopen (opts->group_in_file, "a");
|
||||||
|
fprintf (pFile, "%d,D,", rid); //may want to not use this one
|
||||||
|
fprintf (pFile, "%s", str);
|
||||||
|
fprintf (pFile, ",FQS:%05X.%03X.%06X(%d),Moto\n", wacn, sys, rid, rid);
|
||||||
|
fclose (pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//end Motorola P25 OTA Alias Decoding
|
||||||
|
|
||||||
|
//TODO: Migrate Other OTA Alias functions here
|
||||||
|
|
||||||
|
void l3h_embedded_alias_blocks_phase1 (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t op = (uint8_t)ConvertBitIntoBytes(&lc_bits[0], 8);
|
||||||
|
uint8_t ptr = op-0x32;
|
||||||
|
uint8_t bytes[7]; memset(bytes, 0, sizeof(bytes));
|
||||||
|
for (uint8_t i = 0; i < 7; i++)
|
||||||
|
bytes[i] = (uint8_t)ConvertBitIntoBytes(&lc_bits[16+(i*8)], 8);
|
||||||
|
|
||||||
|
//use +4 offset to match the MAC vPDU since that was already worked out long ago
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+4+(ptr*7), bytes, sizeof(bytes));
|
||||||
|
|
||||||
|
//to be tested
|
||||||
|
if (ptr == 4) //is there always 4 blocks, or is it a variable amount?
|
||||||
|
l3h_embedded_alias_decode(opts, state, slot, 4+28, state->dmr_pdu_sf[slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void l3h_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input)
|
||||||
|
{
|
||||||
|
|
||||||
|
//storage info for storing to groupName, if not available
|
||||||
|
char str[40]; memset (str, 0, sizeof(str));
|
||||||
|
char ttemp[40]; memset (ttemp, 0, sizeof(ttemp));
|
||||||
|
uint8_t wr = 0;
|
||||||
|
uint32_t tsrc = 0, ttg = 0;
|
||||||
|
if (slot == 0 && state->lastsrc != 0) tsrc = state->lastsrc;
|
||||||
|
if (slot == 1 && state->lastsrcR != 0) tsrc = state->lastsrcR;
|
||||||
|
if (slot == 0 && state->lasttg != 0) ttg = state->lasttg;
|
||||||
|
if (slot == 1 && state->lasttgR != 0) ttg = state->lasttgR;
|
||||||
|
|
||||||
|
int8_t ptr = 0;
|
||||||
|
if (tsrc != 0)
|
||||||
|
fprintf (stderr, " TG: %d; SRC: %d; Talker Alias: ", ttg, tsrc);
|
||||||
|
else fprintf (stderr, " TG: UNK; SRC: UNK; Talker Alias: ");
|
||||||
|
for (int8_t i = 4; i <= len; i++)
|
||||||
|
{
|
||||||
|
if ( (input[i] > 0x19) && (input[i] < 0x7F) )
|
||||||
|
fprintf (stderr, "%c", (char)input[i]);
|
||||||
|
else fprintf (stderr, " ");
|
||||||
|
|
||||||
|
if (input[i] == 0x2C) //remove a comma if it exists, change it to a 0x2E dot
|
||||||
|
ttemp[ptr] = 0x2E;
|
||||||
|
else if ( (input[i] > 0x19) && (input[i] < 0x7F) )
|
||||||
|
ttemp[ptr] = input[i];
|
||||||
|
else if (input[i] != 0)
|
||||||
|
ttemp[ptr] = 0x20; //space
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//assign completed talker to a more useful string instead
|
||||||
|
snprintf (str, ptr+1, "%s", ttemp);
|
||||||
|
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == tsrc && tsrc != 0)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].alias, "%s", str);
|
||||||
|
|
||||||
|
//The Duke Energy system may relay two src values, may be a good idea to pick one and stick with it
|
||||||
|
if (tsrc != 0)
|
||||||
|
{
|
||||||
|
for (int16_t i = 0; i < state->group_tally; i++)
|
||||||
|
{
|
||||||
|
if (state->group_array[i].groupNumber == tsrc)
|
||||||
|
{
|
||||||
|
wr = 1; //already in there, so no need to assign it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wr == 0) //not already in there, so save it there now
|
||||||
|
{
|
||||||
|
state->group_array[state->group_tally].groupNumber = tsrc;
|
||||||
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
||||||
|
sprintf (state->group_array[state->group_tally].groupName, "%s", str);
|
||||||
|
state->group_tally++;
|
||||||
|
|
||||||
|
//if we have an opened group file, let's write what info we found into it
|
||||||
|
if (opts->group_in_file[0] != 0) //file is available
|
||||||
|
{
|
||||||
|
FILE * pFile; //file pointer
|
||||||
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
|
pFile = fopen (opts->group_in_file, "a");
|
||||||
|
fprintf (pFile, "%d,D,", tsrc);
|
||||||
|
fprintf (pFile, "%s", str);
|
||||||
|
fprintf (pFile, ",TG:%d,SYS:%03llX,RFSS:%lld,SITE:%lld,Harris\n", ttg, state->p2_sysid, state->p2_rfssid, state->p2_siteid);
|
||||||
|
fclose (pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n WR: %d TG: %d SRC: %d Res: %d Len: %d STR: %s", wr, ttg, tsrc, res, len, str);
|
||||||
|
|
||||||
|
//reset storage
|
||||||
|
memset (state->dmr_pdu_sf[slot], 0, sizeof (state->dmr_pdu_sf[slot]));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void tait_iso7_embedded_alias_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, int16_t len, uint8_t * input)
|
||||||
|
{
|
||||||
|
|
||||||
|
UNUSED(slot);
|
||||||
|
uint8_t alias[24]; memset(alias, 0, sizeof(alias));
|
||||||
|
for (uint8_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
alias[i] = (uint8_t)ConvertBitIntoBytes(&input[16+(i*7)], 7);
|
||||||
|
fprintf (stderr, "%c", alias[i]);
|
||||||
|
if (alias[i] == 0x2C) //change a comma to a dot
|
||||||
|
alias[i] = 0x2E;
|
||||||
|
else if (alias[i] < 0x20) //change any garble / control chars to a space
|
||||||
|
alias[i] = 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
//flag to indicate this already exists in import or group struct
|
||||||
|
uint8_t wr = 0;
|
||||||
|
uint32_t rid = state->lastsrc;
|
||||||
|
uint16_t nac = state->nac;
|
||||||
|
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == rid)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].alias, "%s", alias);
|
||||||
|
|
||||||
|
if (rid != 0)
|
||||||
|
{
|
||||||
|
for (int16_t i = 0; i < state->group_tally; i++)
|
||||||
|
{
|
||||||
|
if (state->group_array[i].groupNumber == rid)
|
||||||
|
{
|
||||||
|
wr = 1; //already in there, so no need to assign it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wr == 0) //not already in there, so save it there now
|
||||||
|
{
|
||||||
|
state->group_array[state->group_tally].groupNumber = rid;
|
||||||
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "D");
|
||||||
|
sprintf (state->group_array[state->group_tally].groupName, "%s", alias);
|
||||||
|
state->group_tally++;
|
||||||
|
|
||||||
|
//if we have an opened group file, let's write what info we found into it
|
||||||
|
if (opts->group_in_file[0] != 0) //file is available
|
||||||
|
{
|
||||||
|
FILE * pFile; //file pointer
|
||||||
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
|
pFile = fopen (opts->group_in_file, "a");
|
||||||
|
fprintf (pFile, "%d,D,", rid); //may want to not use this one
|
||||||
|
fprintf (pFile, "%s,", alias);
|
||||||
|
fprintf (pFile, "%03X,", nac); //if we find this on a trunking system, may want to add the site and rfss id
|
||||||
|
fprintf (pFile, "%s", ",Tait\n");
|
||||||
|
fclose (pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmr_talker_alias_lc_header (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2);
|
||||||
|
uint8_t block_len = (uint8_t)ConvertBitIntoBytes(&lc_bits[18], 5);
|
||||||
|
uint8_t char_size = 0;
|
||||||
|
|
||||||
|
if (format == 0) char_size = 7;
|
||||||
|
else if (format == 1 || format == 2) char_size = 8;
|
||||||
|
else char_size = 16;
|
||||||
|
|
||||||
|
state->dmr_alias_format[slot] = format;
|
||||||
|
state->dmr_alias_block_len[slot] = block_len; //data len, see below
|
||||||
|
state->dmr_alias_char_size[slot] = char_size;
|
||||||
|
|
||||||
|
//load into dmr_pdu_sf as bit wise values for this since iso7 has 49 bits in this header, otherwise, load with 48?
|
||||||
|
if (char_size == 7)
|
||||||
|
memcpy(state->dmr_pdu_sf[slot], lc_bits+23, 49*sizeof(uint8_t));
|
||||||
|
else if (char_size == 8)
|
||||||
|
memcpy(state->dmr_pdu_sf[slot], lc_bits+24, 48*sizeof(uint8_t));
|
||||||
|
else if (char_size == 16)
|
||||||
|
memcpy(state->dmr_pdu_sf[slot], lc_bits+24, 48*sizeof(uint8_t));
|
||||||
|
|
||||||
|
//TEST: The Block Len (Data Lan) value is, according to my interpretation, the number of encoded
|
||||||
|
//character units in the alias, test to verify, but fall back to the ptr index if necessary
|
||||||
|
//this is referenced in 5.4.3 ETSI TS 102 361-2 V2.5.1 (2023-05) 7.2.19 Talker Alias Data Length
|
||||||
|
|
||||||
|
fprintf (stderr, " Slot %d - Talker Alias LC Header; Format %d; Char Len: %d; Char Size: %d;", slot, format, block_len, char_size);
|
||||||
|
|
||||||
|
//Decode the header's alias portion
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
dmr_talker_alias_lc_decode(opts, state, slot, 0, char_size, block_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmr_talker_alias_lc_blocks (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t block_num, uint8_t * lc_bits)
|
||||||
|
{
|
||||||
|
UNUSED(opts); //delete if we don't use this, but may want it if we dump alias to a file later on
|
||||||
|
uint8_t block_len = state->dmr_alias_block_len[slot];
|
||||||
|
uint8_t char_size = state->dmr_alias_char_size[slot];
|
||||||
|
uint16_t ptr = 0;
|
||||||
|
uint16_t end = block_len;
|
||||||
|
|
||||||
|
//Note: The Joann sample only carries block 5, and no header on block 4
|
||||||
|
//another radio on that ham setup also has a broken alias similar, but
|
||||||
|
//the other talkers have the 04 and the sample has a good decode otherwise
|
||||||
|
//debug broken aliasing on ham radio
|
||||||
|
|
||||||
|
// if (char_size == 0) //Enable this is you need to check alias even with missing header (set 7, 8, or 16)
|
||||||
|
// char_size = 8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
22:54:51 Sync: +DMR slot1 [SLOT2] | Color Code=01 | VC6
|
||||||
|
Slot 1 - Talker Alias Block Num: 1; Valid Block; Talker Alias: Joann
|
||||||
|
DMR PDU Payload [05][00][4A][6F][61][6E][6E][00][FF]
|
||||||
|
*/
|
||||||
|
|
||||||
|
//set the pointer to the current index of the dmr_pdu_sf
|
||||||
|
if (char_size == 16)
|
||||||
|
ptr = 48 + (block_num * 56);
|
||||||
|
else if (char_size == 8)
|
||||||
|
ptr = 48 + (block_num * 56);
|
||||||
|
else if (char_size == 7)
|
||||||
|
ptr = 49 + (block_num * 56);
|
||||||
|
|
||||||
|
if (char_size == 0) //unset, no header received
|
||||||
|
fprintf (stderr, " Slot %d - Talker Alias Block Num: %d; Invalid Header;", slot, block_num+1);
|
||||||
|
|
||||||
|
else if (block_num > 3) //invalid block (data error)
|
||||||
|
fprintf (stderr, " Slot %d - Talker Alias Block Num: %d; Invalid Block;", slot, block_num+1);
|
||||||
|
|
||||||
|
else //valid header present, continue
|
||||||
|
{
|
||||||
|
if (char_size == 7)
|
||||||
|
{
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+ptr, lc_bits+16, 56*sizeof(uint8_t));
|
||||||
|
ptr += 56;
|
||||||
|
if (block_len == 0)
|
||||||
|
end = ptr / 7;
|
||||||
|
else end = block_len;
|
||||||
|
}
|
||||||
|
else if (char_size == 8)
|
||||||
|
{
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+ptr, lc_bits+16, 56*sizeof(uint8_t));
|
||||||
|
ptr += 56;
|
||||||
|
if (block_len == 0)
|
||||||
|
end = ptr / 8;
|
||||||
|
else end = block_len;
|
||||||
|
}
|
||||||
|
else if (char_size == 16)
|
||||||
|
{
|
||||||
|
memcpy(state->dmr_pdu_sf[slot]+ptr, lc_bits+16, 56*sizeof(uint8_t));
|
||||||
|
ptr += 56;
|
||||||
|
if (block_len == 0)
|
||||||
|
end = ptr / 16;
|
||||||
|
else end = block_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmr_talker_alias_lc_decode (opts, state, slot, block_num+1, char_size, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decode partial or completed alias
|
||||||
|
void dmr_talker_alias_lc_decode (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t block_num, uint8_t char_size, uint16_t end)
|
||||||
|
{
|
||||||
|
UNUSED(opts);
|
||||||
|
uint16_t i = 0;
|
||||||
|
fprintf (stderr, " Slot %d - Talker Alias Block Num: %d; Valid Block;", slot, block_num+1);
|
||||||
|
fprintf (stderr, " Talker Alias: ");
|
||||||
|
|
||||||
|
char alias_string[500]; memset (alias_string, 0, sizeof(alias_string));
|
||||||
|
sprintf (alias_string, "%s", "");
|
||||||
|
|
||||||
|
if (char_size == 7)
|
||||||
|
{
|
||||||
|
for (i = 0; i < end; i++)
|
||||||
|
{
|
||||||
|
uint8_t character = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][(i*7)], 7);
|
||||||
|
char ch[2]; ch[0] = character; ch[1] = 0;
|
||||||
|
if (character >= 0x20 && character <= 0x7E) //Standard ASCII Set
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%c", character);
|
||||||
|
strcat (alias_string, ch);
|
||||||
|
}
|
||||||
|
// else if (character == 0)
|
||||||
|
// {
|
||||||
|
// strcat (alias_string, " ");
|
||||||
|
// fprintf (stderr, " ");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcat (alias_string, " ");
|
||||||
|
fprintf (stderr, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char_size == 8)
|
||||||
|
{
|
||||||
|
for (i = 0; i < end; i++)
|
||||||
|
{
|
||||||
|
uint8_t character = (uint8_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][(i*8)], 8);
|
||||||
|
char ch[2]; ch[0] = character; ch[1] = 0;
|
||||||
|
// if (character >= 0x20 && character <= 0x7E) //Standard ASCII Set
|
||||||
|
if (character >= 0x20 && character != 0x7F) //allow some extended UTF diacritical characters as well
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%c", character);
|
||||||
|
strcat (alias_string, ch);
|
||||||
|
}
|
||||||
|
// else if (character == 0)
|
||||||
|
// {
|
||||||
|
// strcat (alias_string, " ");
|
||||||
|
// fprintf (stderr, " ");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcat (alias_string, " ");
|
||||||
|
fprintf (stderr, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char_size == 16)
|
||||||
|
{
|
||||||
|
int ptr = 0;
|
||||||
|
setlocale(LC_ALL, ""); //needed when encoded alias contains Chinese (or probably any non-roman charset that isn't default on users terminal)
|
||||||
|
for (i = 0; i < end; i++)
|
||||||
|
{
|
||||||
|
uint16_t character = (uint16_t)ConvertBitIntoBytes(&state->dmr_pdu_sf[slot][(i*16)], 16);
|
||||||
|
|
||||||
|
if (character >= 0x20 && character != 0x7F)
|
||||||
|
fprintf (stderr, "%lc", character);
|
||||||
|
else fprintf (stderr, " ");
|
||||||
|
|
||||||
|
//Encode to UTF-8
|
||||||
|
ptr += utf8_encode(character, alias_string+ptr);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " [%04X], ", character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//assign to string for event history and ncurses display
|
||||||
|
uint32_t source = 0;
|
||||||
|
if (slot == 0)
|
||||||
|
source = state->lastsrc;
|
||||||
|
else source = state->lastsrcR;
|
||||||
|
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == source)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].alias, "%s; ", alias_string);
|
||||||
|
sprintf (state->generic_talker_alias[slot], "Talker Alias: %s; ", alias_string);
|
||||||
|
|
||||||
|
}
|
||||||
212
src/dsd_audio.c
212
src/dsd_audio.c
@@ -23,6 +23,9 @@ pa_sample_spec zz;
|
|||||||
pa_sample_spec cc;
|
pa_sample_spec cc;
|
||||||
pa_sample_spec ff; //float
|
pa_sample_spec ff; //float
|
||||||
|
|
||||||
|
//pulse audio buffer attributes (input latency)
|
||||||
|
pa_buffer_attr lt;
|
||||||
|
|
||||||
void closePulseOutput (dsd_opts * opts)
|
void closePulseOutput (dsd_opts * opts)
|
||||||
{
|
{
|
||||||
pa_simple_free (opts->pulse_digi_dev_out);
|
pa_simple_free (opts->pulse_digi_dev_out);
|
||||||
@@ -38,6 +41,12 @@ void closePulseInput (dsd_opts * opts)
|
|||||||
void openPulseOutput(dsd_opts * opts)
|
void openPulseOutput(dsd_opts * opts)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * dev = NULL;
|
||||||
|
if (opts->pa_output_idx[0] != 0)
|
||||||
|
dev = opts->pa_output_idx;
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
ss.format = PA_SAMPLE_S16NE;
|
ss.format = PA_SAMPLE_S16NE;
|
||||||
ss.channels = opts->pulse_raw_out_channels;
|
ss.channels = opts->pulse_raw_out_channels;
|
||||||
ss.rate = opts->pulse_raw_rate_out;
|
ss.rate = opts->pulse_raw_rate_out;
|
||||||
@@ -52,30 +61,142 @@ void openPulseOutput(dsd_opts * opts)
|
|||||||
|
|
||||||
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
|
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
|
||||||
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
|
||||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
|
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, dev, "Analog", &ss, 0, NULL, &err);
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Err: %d; %s; ", err, pa_strerror(err));
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
fprintf (stderr, "Please make sure the Pulse Audio Server Backend is running first.");
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
pa_channel_map* fl = 0; //NULL and 0 are same in this context
|
pa_channel_map* fl = 0; //NULL and 0 are same in this context
|
||||||
pa_channel_map* ss = 0; //NULL and 0 are same in this context
|
pa_channel_map* ss = 0; //NULL and 0 are same in this context
|
||||||
|
|
||||||
if (opts->floating_point == 0)
|
if (opts->floating_point == 0 && opts->analog_only == 0)
|
||||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, ss, NULL, NULL);
|
{
|
||||||
|
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, dev, opts->output_name, &tt, ss, NULL, &err);
|
||||||
|
|
||||||
if (opts->floating_point == 1)
|
if (err != 0)
|
||||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &ff, fl, NULL, NULL);
|
{
|
||||||
|
fprintf (stderr, "Err: %d; %s; ", err, pa_strerror(err));
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
fprintf (stderr, "Please make sure the Pulse Audio Server Backend is running first.");
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->floating_point == 1 && opts->analog_only == 0)
|
||||||
|
{
|
||||||
|
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, dev, opts->output_name, &ff, fl, NULL, &err);
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Err: %d; %s; ", err, pa_strerror(err));
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
fprintf (stderr, "Please make sure the Pulse Audio Server Backend is running first.");
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void openPulseInput(dsd_opts * opts)
|
void openPulseInput(dsd_opts * opts)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * dev = NULL;
|
||||||
|
if (opts->pa_input_idx[0] != 0)
|
||||||
|
dev = opts->pa_input_idx;
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
cc.format = PA_SAMPLE_S16NE;
|
cc.format = PA_SAMPLE_S16NE;
|
||||||
cc.channels = opts->pulse_digi_in_channels;
|
cc.channels = opts->pulse_digi_in_channels;
|
||||||
cc.rate = opts->pulse_digi_rate_in; //48000
|
cc.rate = opts->pulse_digi_rate_in; //48000
|
||||||
|
|
||||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, opts->output_name, &cc, NULL, NULL, NULL);
|
//adjust input latency settings (defaults are all -1 to let server set these automatically, but without pavucontrol open, this is approx 2s)
|
||||||
|
//setting fragsize to 960 for 48000 input seems to do the trick to allow a much faster latency without underrun, may need adjusting if
|
||||||
|
//modifying the input rate (will only apply IF using pulse audio input, and not any other input method)
|
||||||
|
|
||||||
|
//TODO: set fragsize vs expected input rate if required in the future
|
||||||
|
//NOTE: If users report any underrun conditions, then either change 960 back to -1, or pass NULL instead of <
|
||||||
|
|
||||||
|
//https://freedesktop.org/software/pulseaudio/doxygen/structpa__buffer__attr.html
|
||||||
|
|
||||||
|
//for now, only going to modify the fragsize if using the encoder, else, let the pa server set it automatically
|
||||||
|
// if (opts->m17encoder == 1)
|
||||||
|
// lt.fragsize = 960*5;
|
||||||
|
// else lt.fragsize = -1;
|
||||||
|
|
||||||
|
//test doing it universally, fall back to above if needed
|
||||||
|
lt.fragsize = 960*5;
|
||||||
|
lt.maxlength = -1;
|
||||||
|
lt.prebuf = -1;
|
||||||
|
lt.tlength = -1;
|
||||||
|
// if (opts->m17encoder == 1)
|
||||||
|
// opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME4", PA_STREAM_RECORD, dev, "M17 Voice Input", &cc, NULL, <, &err);
|
||||||
|
// else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||||
|
|
||||||
|
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, <, &err);
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Err: %d; %s; ", err, pa_strerror(err));
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
fprintf (stderr, "Please make sure the Pulse Audio Server Backend is running first.");
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// if (opts->m17encoder == 1)
|
||||||
|
// {
|
||||||
|
// unsigned long long int latency = pa_simple_get_latency (opts->pulse_digi_dev_in, NULL);
|
||||||
|
// fprintf (stderr, "Pulse Audio Input Latency: %05lld;", latency);
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse_pulse_input_string (dsd_opts * opts, char * input)
|
||||||
|
{
|
||||||
|
char * curr;
|
||||||
|
curr = strtok(input, ":");
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
strncpy (opts->pa_input_idx, curr, 99);
|
||||||
|
opts->pa_input_idx[99] = 0;
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "Pulse Input Device: %s; ", opts->pa_input_idx);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_pulse_output_string (dsd_opts * opts, char * input)
|
||||||
|
{
|
||||||
|
char * curr;
|
||||||
|
curr = strtok(input, ":");
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
strncpy (opts->pa_output_idx, curr, 99);
|
||||||
|
opts->pa_output_idx[99] = 0;
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
fprintf (stderr, "Pulse Output Device: %s; ", opts->pa_output_idx);
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// macOS does not support OSS (/dev/dsp).
|
||||||
|
// Provide a stub so callers can link while using Pulse/CoreAudio backends.
|
||||||
|
void openOSSOutput(dsd_opts *opts)
|
||||||
|
{
|
||||||
|
(void)opts;
|
||||||
|
}
|
||||||
|
#else
|
||||||
void openOSSOutput (dsd_opts * opts)
|
void openOSSOutput (dsd_opts * opts)
|
||||||
{
|
{
|
||||||
int fmt;
|
int fmt;
|
||||||
@@ -94,6 +215,7 @@ void openOSSOutput (dsd_opts * opts)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fmt = 0;
|
fmt = 0;
|
||||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
||||||
{
|
{
|
||||||
@@ -125,7 +247,7 @@ void openOSSOutput (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts->audio_in_type != 5) //split == 1
|
if (opts->audio_in_type != 5 || opts->split == 1) //split == 1
|
||||||
{
|
{
|
||||||
|
|
||||||
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
|
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
|
||||||
@@ -190,6 +312,7 @@ void openOSSOutput (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
processAudio (dsd_opts * opts, dsd_state * state)
|
processAudio (dsd_opts * opts, dsd_state * state)
|
||||||
@@ -539,6 +662,42 @@ void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//short Mono to Stereo version for new static .wav files in stereo format for TDMA
|
||||||
|
void writeSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
short aout_buf[160];
|
||||||
|
short *aout_buf_p;
|
||||||
|
|
||||||
|
aout_buf_p = aout_buf;
|
||||||
|
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||||
|
|
||||||
|
for (n = 0; n < 160; n++)
|
||||||
|
{
|
||||||
|
if (*state->audio_out_temp_buf_p > (float) 32767)
|
||||||
|
{
|
||||||
|
*state->audio_out_temp_buf_p = (float) 32767;
|
||||||
|
}
|
||||||
|
else if (*state->audio_out_temp_buf_p < (float) -32768)
|
||||||
|
{
|
||||||
|
*state->audio_out_temp_buf_p = (float) -32768;
|
||||||
|
}
|
||||||
|
*aout_buf_p = (short) *state->audio_out_temp_buf_p;
|
||||||
|
aout_buf_p++;
|
||||||
|
state->audio_out_temp_buf_p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
short ss[320];
|
||||||
|
for (n = 0; n < 160; n++)
|
||||||
|
{
|
||||||
|
ss[(n*2)+0] = aout_buf[n];
|
||||||
|
ss[(n*2)+1] = aout_buf[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
sf_write_short(opts->wav_out_f, ss, 320);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
|
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
UNUSED(state);
|
||||||
@@ -575,7 +734,7 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
if (state->audio_out_idx > opts->delay)
|
if (state->audio_out_idx > opts->delay)
|
||||||
{
|
{
|
||||||
if (opts->audio_out_type == 5) //OSS
|
if (opts->audio_out_type == 5 || opts->audio_out_type == 1) //OSS
|
||||||
{
|
{
|
||||||
//OSS 48k/1
|
//OSS 48k/1
|
||||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||||
@@ -712,6 +871,11 @@ openAudioInDevice (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (strncmp(opts->audio_in_dev, "m17udp", 6) == 0)
|
||||||
|
{
|
||||||
|
opts->audio_in_type = 9; //NULL audio device
|
||||||
|
}
|
||||||
|
|
||||||
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
|
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
|
||||||
{
|
{
|
||||||
opts->audio_in_type = 8;
|
opts->audio_in_type = 8;
|
||||||
@@ -785,7 +949,7 @@ openAudioInDevice (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//test .rrc files with hardset wav file settings
|
//test .rrc files with hardset wav file settings
|
||||||
else if (strncmp(extension, ".rrc", 3) == 0)
|
else if (strncmp(extension, ".rrc", 4) == 0)
|
||||||
{
|
{
|
||||||
//debug
|
//debug
|
||||||
fprintf (stderr, "Opening M17 .rrc headless wav file\n");
|
fprintf (stderr, "Opening M17 .rrc headless wav file\n");
|
||||||
@@ -805,19 +969,19 @@ openAudioInDevice (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: test .sym files as symbol capture .bin files
|
//Open .raw files as a float input type
|
||||||
else if (strncmp(extension, ".sym", 3) == 0)
|
else if (strncmp(extension, ".raw", 4) == 0)
|
||||||
{
|
{
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
|
fprintf (stderr,"Error, couldn't open raw (float) file %s\n", opts->audio_in_dev);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (S_ISREG(stat_buf.st_mode))
|
if (S_ISREG(stat_buf.st_mode))
|
||||||
{
|
{
|
||||||
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||||
opts->audio_in_type = 4; //symbol capture bin files
|
opts->audio_in_type = 44; //float symbol input
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -825,7 +989,27 @@ openAudioInDevice (dsd_opts * opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strncmp(extension, ".bin", 3) == 0)
|
//Open .raw files as a float input type
|
||||||
|
else if (strncmp(extension, ".sym", 4) == 0)
|
||||||
|
{
|
||||||
|
struct stat stat_buf;
|
||||||
|
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error, couldn't open sym (float) file %s\n", opts->audio_in_dev);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (S_ISREG(stat_buf.st_mode))
|
||||||
|
{
|
||||||
|
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||||
|
opts->audio_in_type = 44; //float symbol input
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opts->audio_in_type = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (strncmp(extension, ".bin", 4) == 0)
|
||||||
{
|
{
|
||||||
struct stat stat_buf;
|
struct stat stat_buf;
|
||||||
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||||
|
|||||||
1118
src/dsd_audio2.c
1118
src/dsd_audio2.c
File diff suppressed because it is too large
Load Diff
@@ -267,7 +267,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
|
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
|
||||||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
|
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
|
||||||
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 31) ||
|
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 31) ||
|
||||||
(state->synctype == 36) || (state->synctype == 99) )
|
(state->synctype == 77) || (state->synctype == 87) ||(state->synctype == 36) ||
|
||||||
|
(state->synctype == 99) )
|
||||||
|
|
||||||
{
|
{
|
||||||
// 1 -P25p1
|
// 1 -P25p1
|
||||||
@@ -280,6 +281,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
// 29 -NXDN (inverted FSW)
|
// 29 -NXDN (inverted FSW)
|
||||||
// 31 -YSF
|
// 31 -YSF
|
||||||
// 36 -P25p2
|
// 36 -P25p2
|
||||||
|
// 77 -M17 BRT
|
||||||
|
// 87 -M17 PKT
|
||||||
// 99 -M17 Preamble
|
// 99 -M17 Preamble
|
||||||
|
|
||||||
int valid;
|
int valid;
|
||||||
@@ -349,6 +352,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
|||||||
// 28 +NXND (FSW)
|
// 28 +NXND (FSW)
|
||||||
// 30 +YSF
|
// 30 +YSF
|
||||||
// 35 +p25p2
|
// 35 +p25p2
|
||||||
|
// 76 +M17 BRT
|
||||||
|
// 86 +M17 PKT
|
||||||
// 98 +M17 Preamble
|
// 98 +M17 Preamble
|
||||||
|
|
||||||
int valid;
|
int valid;
|
||||||
|
|||||||
870
src/dsd_events.c
Normal file
870
src/dsd_events.c
Normal file
@@ -0,0 +1,870 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dsd_events.c
|
||||||
|
* DSD-FME event history init, watchdog, push, and related functions
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2025-05 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
#include "git_ver.h"
|
||||||
|
#include "synctype.h"
|
||||||
|
|
||||||
|
//init each event history struct passed into here
|
||||||
|
void init_event_history (Event_History_I * event_struct, uint8_t start, uint8_t stop)
|
||||||
|
{
|
||||||
|
for (uint8_t i = start; i < stop; i++)
|
||||||
|
{
|
||||||
|
event_struct->Event_History_Items[i].write = 0;
|
||||||
|
event_struct->Event_History_Items[i].color_pair = 4;
|
||||||
|
event_struct->Event_History_Items[i].systype = -1;
|
||||||
|
event_struct->Event_History_Items[i].subtype = -1;
|
||||||
|
event_struct->Event_History_Items[i].sys_id1 = 0;
|
||||||
|
event_struct->Event_History_Items[i].sys_id2 = 0;
|
||||||
|
event_struct->Event_History_Items[i].sys_id3 = 0;
|
||||||
|
event_struct->Event_History_Items[i].sys_id4 = 0;
|
||||||
|
event_struct->Event_History_Items[i].sys_id5 = 0;
|
||||||
|
event_struct->Event_History_Items[i].gi = 0;
|
||||||
|
event_struct->Event_History_Items[i].enc = 0;
|
||||||
|
event_struct->Event_History_Items[i].enc_alg = 0;
|
||||||
|
event_struct->Event_History_Items[i].enc_key = 0;
|
||||||
|
event_struct->Event_History_Items[i].mi = 0;
|
||||||
|
event_struct->Event_History_Items[i].svc = 0;
|
||||||
|
event_struct->Event_History_Items[i].source_id = 0;
|
||||||
|
event_struct->Event_History_Items[i].target_id = 0;
|
||||||
|
sprintf (event_struct->Event_History_Items[i].src_str, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].tgt_str, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].t_name, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].s_name, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].t_mode, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].s_mode, "%s", "BUMBLEBEETUNA");
|
||||||
|
event_struct->Event_History_Items[i].channel = 0;
|
||||||
|
event_struct->Event_History_Items[i].event_time = 0;
|
||||||
|
|
||||||
|
memset (event_struct->Event_History_Items[i].pdu, 0, sizeof(event_struct->Event_History_Items[0].pdu));
|
||||||
|
sprintf (event_struct->Event_History_Items[i].sysid_string, "%s", "");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].alias, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].gps_s, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].text_message, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].event_string, "%s", "BUMBLEBEETUNA");
|
||||||
|
sprintf (event_struct->Event_History_Items[i].internal_str, "%s", "BUMBLEBEETUNA");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_event_history (Event_History_I * event_struct)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Fixed, had it going in the wrong direction first time
|
||||||
|
for (uint8_t i = 254; i >= 1; i--)
|
||||||
|
{
|
||||||
|
event_struct->Event_History_Items[i].write = event_struct->Event_History_Items[i-1].write;
|
||||||
|
event_struct->Event_History_Items[i].color_pair = event_struct->Event_History_Items[i-1].color_pair;
|
||||||
|
event_struct->Event_History_Items[i].systype = event_struct->Event_History_Items[i-1].systype;
|
||||||
|
event_struct->Event_History_Items[i].subtype = event_struct->Event_History_Items[i-1].subtype;
|
||||||
|
event_struct->Event_History_Items[i].sys_id1 = event_struct->Event_History_Items[i-1].sys_id1;
|
||||||
|
event_struct->Event_History_Items[i].sys_id2 = event_struct->Event_History_Items[i-1].sys_id2;
|
||||||
|
event_struct->Event_History_Items[i].sys_id3 = event_struct->Event_History_Items[i-1].sys_id3;
|
||||||
|
event_struct->Event_History_Items[i].sys_id4 = event_struct->Event_History_Items[i-1].sys_id4;
|
||||||
|
event_struct->Event_History_Items[i].sys_id5 = event_struct->Event_History_Items[i-1].sys_id5;
|
||||||
|
event_struct->Event_History_Items[i].gi = event_struct->Event_History_Items[i-1].gi;
|
||||||
|
event_struct->Event_History_Items[i].enc = event_struct->Event_History_Items[i-1].enc;
|
||||||
|
event_struct->Event_History_Items[i].enc_alg = event_struct->Event_History_Items[i-1].enc_alg;
|
||||||
|
event_struct->Event_History_Items[i].enc_key = event_struct->Event_History_Items[i-1].enc_key;
|
||||||
|
event_struct->Event_History_Items[i].mi = event_struct->Event_History_Items[i-1].mi;
|
||||||
|
event_struct->Event_History_Items[i].svc = event_struct->Event_History_Items[i-1].svc;
|
||||||
|
event_struct->Event_History_Items[i].source_id = event_struct->Event_History_Items[i-1].source_id;
|
||||||
|
event_struct->Event_History_Items[i].target_id = event_struct->Event_History_Items[i-1].target_id;
|
||||||
|
sprintf (event_struct->Event_History_Items[i].src_str, "%s", event_struct->Event_History_Items[i-1].src_str);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].tgt_str, "%s", event_struct->Event_History_Items[i-1].tgt_str);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].t_name, "%s", event_struct->Event_History_Items[i-1].t_name);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].s_name, "%s", event_struct->Event_History_Items[i-1].s_name);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].t_mode, "%s", event_struct->Event_History_Items[i-1].t_mode);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].s_mode, "%s", event_struct->Event_History_Items[i-1].s_mode);
|
||||||
|
event_struct->Event_History_Items[i].channel = event_struct->Event_History_Items[i-1].channel;
|
||||||
|
event_struct->Event_History_Items[i].event_time = event_struct->Event_History_Items[i+1].event_time;
|
||||||
|
|
||||||
|
memcpy (event_struct->Event_History_Items[i].pdu, event_struct->Event_History_Items[i-1].pdu, sizeof(event_struct->Event_History_Items[0].pdu));
|
||||||
|
sprintf (event_struct->Event_History_Items[i].sysid_string, "%s", event_struct->Event_History_Items[i-1].sysid_string);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].alias, "%s", event_struct->Event_History_Items[i-1].alias);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].gps_s, "%s", event_struct->Event_History_Items[i-1].gps_s);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].text_message, "%s", event_struct->Event_History_Items[i-1].text_message);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].event_string, "%s", event_struct->Event_History_Items[i-1].event_string);
|
||||||
|
sprintf (event_struct->Event_History_Items[i].internal_str, "%s", event_struct->Event_History_Items[i-1].internal_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_event_to_log_file (dsd_opts * opts, dsd_state * state, uint8_t slot, uint8_t swrite, char * event_string) //pass completed event string here that is in the struct
|
||||||
|
{
|
||||||
|
|
||||||
|
//open log file
|
||||||
|
FILE * event_log_file;
|
||||||
|
event_log_file = fopen(opts->event_out_file, "a");
|
||||||
|
|
||||||
|
fprintf (event_log_file, "%s ", event_string);
|
||||||
|
if (swrite == 1)
|
||||||
|
fprintf (event_log_file, "Slot %d; ", slot+1);
|
||||||
|
fprintf (event_log_file,"\n");
|
||||||
|
|
||||||
|
char text_string[2000]; sprintf (text_string, "%s", "BUMBLEBEETUNA");
|
||||||
|
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].text_message, 13) != 0)
|
||||||
|
fprintf (event_log_file, "%s \n", state->event_history_s[slot].Event_History_Items[0].text_message);
|
||||||
|
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].alias, 13) != 0)
|
||||||
|
fprintf (event_log_file, " Talker Alias: %s \n", state->event_history_s[slot].Event_History_Items[0].alias);
|
||||||
|
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].gps_s, 13) != 0)
|
||||||
|
fprintf (event_log_file, " GPS: %s \n", state->event_history_s[slot].Event_History_Items[0].gps_s);
|
||||||
|
if (strncmp(text_string, state->event_history_s[slot].Event_History_Items[0].internal_str, 13) != 0)
|
||||||
|
fprintf (event_log_file, " DSD-FME: %s \n", state->event_history_s[slot].Event_History_Items[0].internal_str);
|
||||||
|
|
||||||
|
//flush and close log file
|
||||||
|
fflush (event_log_file);
|
||||||
|
fclose (event_log_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run once per loop to check for and push and update event history
|
||||||
|
void watchdog_event_history (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||||||
|
{
|
||||||
|
|
||||||
|
//create a pointer to the current slot event history
|
||||||
|
Event_History_I * event_struct = &state->event_history_s[slot];
|
||||||
|
|
||||||
|
//is this a TDMA slot (append Slot value to end of written event history)
|
||||||
|
uint8_t swrite = 0;
|
||||||
|
|
||||||
|
//who is currently talking
|
||||||
|
uint32_t source_id = 0;
|
||||||
|
|
||||||
|
//last values pulled from the event history
|
||||||
|
uint32_t last_source_id = event_struct->Event_History_Items[0].source_id;
|
||||||
|
|
||||||
|
if (slot == 0)
|
||||||
|
source_id = state->lastsrc;
|
||||||
|
else
|
||||||
|
source_id = state->lastsrcR;
|
||||||
|
|
||||||
|
//if DMR BS or P25P2, then flag the swrite, so write can append slot value to event history log //|| state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 MS
|
||||||
|
if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13)
|
||||||
|
swrite = 1;
|
||||||
|
|
||||||
|
else if (state->lastsynctype == 35 || state->lastsynctype == 36)
|
||||||
|
swrite = 1;
|
||||||
|
|
||||||
|
if (slot == 0) //BUGFIX: generic catch on FDMA systems so that we don't write duplicate data to slot 2 event history
|
||||||
|
{
|
||||||
|
//NXDN RID (TODO: Changeover to lastsrc later on)
|
||||||
|
if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||||||
|
source_id = state->nxdn_last_rid;
|
||||||
|
|
||||||
|
if (state->lastsynctype == 30 || state->lastsynctype == 31) //YSF Fusion
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
if (strncmp(state->ysf_src, " ", 10) != 0) //if this field does not have ten spaces in it
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 11; i++)
|
||||||
|
source_id += state->ysf_src[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //M17 STR
|
||||||
|
{
|
||||||
|
source_id = (uint32_t)state->m17_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
for (uint8_t i = 0; i < 12; i++)
|
||||||
|
source_id += state->dstar_src[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
|
||||||
|
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||||||
|
if (strncmp(state->dstar_src, " ", 8) == 0)
|
||||||
|
source_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
for (uint8_t i = 0; i < 20; i++)
|
||||||
|
source_id += state->dpmr_caller_id[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
|
||||||
|
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||||||
|
if (strncmp(state->dpmr_caller_id, " ", 6) == 0)
|
||||||
|
source_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
if (opts->p25_is_tuned == 1)
|
||||||
|
source_id = state->lastsrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//call alert beep when new call detected
|
||||||
|
if (last_source_id == 0 && source_id != 0 && opts->call_alert == 1)
|
||||||
|
beeper (opts, state, slot, 40, 86, 3);
|
||||||
|
|
||||||
|
if (source_id != last_source_id && last_source_id != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (opts->event_out_file[0] != 0)
|
||||||
|
write_event_to_log_file(opts, state, slot, swrite, event_struct->Event_History_Items[0].event_string);
|
||||||
|
|
||||||
|
event_struct->Event_History_Items[0].write = 1; //written, or pushed at this point
|
||||||
|
|
||||||
|
if (opts->static_wav_file == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (slot == 0 && opts->wav_out_f != NULL)
|
||||||
|
{
|
||||||
|
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, event_struct);
|
||||||
|
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (slot == 1 && opts->wav_out_fR != NULL)
|
||||||
|
{
|
||||||
|
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, event_struct);
|
||||||
|
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
push_event_history (event_struct);
|
||||||
|
init_event_history (event_struct, 0, 1);
|
||||||
|
|
||||||
|
//clear out some strings and things
|
||||||
|
memset(state->ysf_txt, 0, sizeof(state->ysf_txt));
|
||||||
|
memset(state->dstar_gps, 0, sizeof(state->dstar_gps));
|
||||||
|
memset(state->dstar_txt, 0, sizeof(state->dstar_txt));
|
||||||
|
state->gi[slot] = -1; //return to an unset value
|
||||||
|
|
||||||
|
//end of voice call alert
|
||||||
|
if (opts->call_alert == 1)
|
||||||
|
beeper (opts, state, slot, 40, 86, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//similar to above, but constantly testing and checking the most recent event only
|
||||||
|
//this will hopefully be more useful when dealing with an ongoing event with
|
||||||
|
//features that update over time with embedded signalling, etc
|
||||||
|
void watchdog_event_current (dsd_opts * opts, dsd_state * state, uint8_t slot)
|
||||||
|
{
|
||||||
|
|
||||||
|
//create a pointer to the current slot event history
|
||||||
|
Event_History_I * event_struct = &state->event_history_s[slot];
|
||||||
|
|
||||||
|
//ncurses color pairs
|
||||||
|
uint8_t color_pair = 4; //default voice color (unknown gi)
|
||||||
|
if (state->gi[slot] == 1)
|
||||||
|
color_pair = 4; //default private voice color
|
||||||
|
else if (state->gi[slot] == 0)
|
||||||
|
color_pair = 4; //default group voice color
|
||||||
|
|
||||||
|
//TODO: Flesh out more later on.
|
||||||
|
uint32_t source_id = 0;
|
||||||
|
uint32_t target_id = 0;
|
||||||
|
char src_str[200]; memset (src_str, 0, sizeof(src_str));
|
||||||
|
sprintf (src_str, "%s", "BUMBLEBEETUNA");
|
||||||
|
char tgt_str[200]; memset (tgt_str, 0, sizeof(tgt_str));
|
||||||
|
sprintf (tgt_str, "%s", "BUMBLEBEETUNA");
|
||||||
|
|
||||||
|
//group import items
|
||||||
|
char t_name[200]; memset (t_name, 0, sizeof(t_name));
|
||||||
|
sprintf (t_name, "%s", "BUMBLEBEETUNA");
|
||||||
|
char s_name[200]; memset (s_name, 0, sizeof(s_name));
|
||||||
|
sprintf (s_name, "%s", "BUMBLEBEETUNA");
|
||||||
|
char t_mode[200]; memset (t_mode, 0, sizeof(t_mode));
|
||||||
|
sprintf (t_mode, "%s", "BUMBLEBEETUNA");
|
||||||
|
char s_mode[200]; memset (s_mode, 0, sizeof(s_mode));
|
||||||
|
sprintf (s_mode, "%s", "BUMBLEBEETUNA");
|
||||||
|
|
||||||
|
uint16_t svc_opts = 0;
|
||||||
|
uint8_t subtype = 0;
|
||||||
|
uint8_t mfid = 0;
|
||||||
|
uint32_t sys_id1 = 0;
|
||||||
|
uint32_t sys_id2 = 0;
|
||||||
|
uint32_t sys_id3 = 0;
|
||||||
|
uint32_t sys_id4 = 0;
|
||||||
|
uint32_t sys_id5 = 0;
|
||||||
|
|
||||||
|
uint32_t channel = 0;
|
||||||
|
|
||||||
|
uint8_t enc = 0;
|
||||||
|
uint8_t alg_id = 0;
|
||||||
|
uint16_t key_id = 0;
|
||||||
|
unsigned long long int mi;
|
||||||
|
|
||||||
|
char sysid_string[200]; memset(sysid_string, 0, sizeof(sysid_string));
|
||||||
|
sprintf (sysid_string, "%s", "");
|
||||||
|
|
||||||
|
if (slot == 0)
|
||||||
|
{
|
||||||
|
source_id = state->lastsrc;
|
||||||
|
target_id = state->lasttg;
|
||||||
|
|
||||||
|
subtype = state->dmrburstL;
|
||||||
|
mfid = state->dmr_fid;
|
||||||
|
|
||||||
|
svc_opts = state->dmr_so;
|
||||||
|
enc = (svc_opts >> 6) & 1;
|
||||||
|
alg_id = state->payload_algid;
|
||||||
|
key_id = (uint16_t)state->payload_keyid;
|
||||||
|
|
||||||
|
mi = state->payload_mi;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source_id = state->lastsrcR;
|
||||||
|
target_id = state->lasttgR;
|
||||||
|
|
||||||
|
subtype = state->dmrburstR;
|
||||||
|
mfid = state->dmr_fidR;
|
||||||
|
|
||||||
|
svc_opts = state->dmr_soR;
|
||||||
|
enc = (svc_opts >> 6) & 1;
|
||||||
|
|
||||||
|
alg_id = state->payload_algidR;
|
||||||
|
key_id = (uint16_t)state->payload_keyidR;
|
||||||
|
mi = state->payload_miR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if P25 (if not P25, then these will all be zero anyways)
|
||||||
|
sys_id1 = state->p2_wacn;
|
||||||
|
sys_id2 = state->p2_sysid;
|
||||||
|
if (state->nac != 0)
|
||||||
|
sys_id3 = state->nac; //same as state->p2_cc, but zeroes out when no signal or error
|
||||||
|
else sys_id3 = state->p2_cc;
|
||||||
|
sys_id4 = state->p2_rfssid;
|
||||||
|
sys_id5 = state->p2_siteid;
|
||||||
|
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (sysid_string, "P25_%05X%03X%03X_%d_%d", sys_id1, sys_id2, sys_id3, sys_id4, sys_id5);
|
||||||
|
else sprintf (sysid_string, "P25_%03X", sys_id3);
|
||||||
|
|
||||||
|
if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13 ||
|
||||||
|
state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 )
|
||||||
|
{
|
||||||
|
sys_id1 = state->dmr_t3_syscode;
|
||||||
|
sys_id2 = state->dmr_color_code;
|
||||||
|
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (sysid_string, "DMR_%X_CC_%d", sys_id1, sys_id2);
|
||||||
|
else sprintf (sysid_string, "DMR_CC_%d", sys_id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == 0) //BUGFIX: generic catch on FDMA systems so that we don't write duplicate data to slot 2 event history
|
||||||
|
{
|
||||||
|
//NXDN RID (TODO: Changeover to lastsrc and lasttg later on)
|
||||||
|
if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||||||
|
{
|
||||||
|
source_id = state->nxdn_last_rid;
|
||||||
|
target_id = state->nxdn_last_tg;
|
||||||
|
if (state->nxdn_cipher_type != 0)
|
||||||
|
enc = 1;
|
||||||
|
alg_id = state->nxdn_cipher_type;
|
||||||
|
key_id = state->nxdn_key;
|
||||||
|
|
||||||
|
sys_id1 = state->nxdn_location_site_code;
|
||||||
|
sys_id2 = state->nxdn_location_sys_code;
|
||||||
|
sys_id3 = state->nxdn_last_ran; //might be an issue on conventional systems that have a different RAN on the tx_rel or idle data bursts
|
||||||
|
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (sysid_string, "NXDN_%d_%d_RAN_%d", sys_id2, sys_id1, sys_id3);
|
||||||
|
else sprintf (sysid_string, "NXDN_RAN_%d", sys_id3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 30 || state->lastsynctype == 31) //YSF Fusion
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
if (strncmp(state->ysf_src, " ", 10) != 0) //if this field does not have ten spaces in it
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 11; i++)
|
||||||
|
source_id += state->ysf_src[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
}
|
||||||
|
|
||||||
|
//WIP: If Text, compile it here (still having issues with an empty txt string making a line break)
|
||||||
|
uint8_t k = 0; char ysf_emp[21][21]; memset(ysf_emp, 0, sizeof(ysf_emp));
|
||||||
|
if (memcmp(ysf_emp, state->ysf_txt, sizeof(state->ysf_txt)) != 0)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 4; i < 8; i++)
|
||||||
|
{
|
||||||
|
for (uint8_t j = 0; j < 20; j++)
|
||||||
|
{
|
||||||
|
if (state->ysf_txt[i][j] != 0x2A)
|
||||||
|
event_struct->Event_History_Items[0].text_message[k++] = state->ysf_txt[i][j];
|
||||||
|
else event_struct->Event_History_Items[0].text_message[k++] = 0x20; //space
|
||||||
|
|
||||||
|
}
|
||||||
|
event_struct->Event_History_Items[0].text_message[k] = 0; //terminate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else sprintf (event_struct->Event_History_Items[0].text_message, "%s", "BUMBLEBEETUNA");
|
||||||
|
|
||||||
|
sprintf (sysid_string, "%s", "YSF");
|
||||||
|
|
||||||
|
char temp_str[20];
|
||||||
|
memset(temp_str, 0, sizeof(temp_str));
|
||||||
|
|
||||||
|
//set src string as a non-spaced non-garbo char string
|
||||||
|
for (uint8_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (state->ysf_src[i] == 0x20) //spaces to underscore
|
||||||
|
temp_str[i] = 0x5F;
|
||||||
|
else if (state->ysf_src[i] > 0x20 && state->ysf_src[i] < 0x7F) //copy normal ascii range characters
|
||||||
|
temp_str[i] = state->ysf_src[i];
|
||||||
|
else if (state->ysf_src[i] == 0) break; //hit the terminator, so stop
|
||||||
|
else temp_str[i] = 0x5F; //unknown to underscore
|
||||||
|
}
|
||||||
|
sprintf (src_str, "%s", temp_str);
|
||||||
|
|
||||||
|
//same for tgt str
|
||||||
|
memset(temp_str, 0, sizeof(temp_str));
|
||||||
|
for (uint8_t i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (state->ysf_tgt[i] == 0x20) //spaces to underscore
|
||||||
|
temp_str[i] = 0x5F;
|
||||||
|
else if (state->ysf_tgt[i] > 0x20 && state->ysf_tgt[i] < 0x7F) //copy normal ascii range characters
|
||||||
|
temp_str[i] = state->ysf_tgt[i];
|
||||||
|
else if (state->ysf_tgt[i] == 0) break; //hit the terminator, so stop
|
||||||
|
else temp_str[i] = 0x5F; //unknown to underscore
|
||||||
|
}
|
||||||
|
sprintf (tgt_str, "%s", temp_str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //M17 STR
|
||||||
|
{
|
||||||
|
target_id = (uint32_t)state->m17_dst;
|
||||||
|
source_id = (uint32_t)state->m17_src;
|
||||||
|
sys_id1 = state->m17_can;
|
||||||
|
sprintf (sysid_string, "M17_CAN_%d", sys_id1);
|
||||||
|
sprintf (src_str, "%s", state->m17_src_csd);
|
||||||
|
sprintf (tgt_str, "%s", state->m17_dst_csd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
for (uint8_t i = 0; i < 12; i++)
|
||||||
|
source_id += state->dstar_src[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
|
||||||
|
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||||||
|
if (strncmp(state->dstar_src, " ", 8) == 0)
|
||||||
|
source_id = 0;
|
||||||
|
|
||||||
|
sprintf (sysid_string, "%s", "DSTAR");
|
||||||
|
|
||||||
|
char temp_str[20];
|
||||||
|
memset(temp_str, 0, sizeof(temp_str));
|
||||||
|
|
||||||
|
//set src string as a non-spaced non-garbo char string
|
||||||
|
for (uint8_t i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
if (state->dstar_src[i] == 0x20) //spaces to underscore
|
||||||
|
temp_str[i] = 0x5F;
|
||||||
|
else if (state->dstar_src[i] > 0x20 && state->dstar_src[i] < 0x7F) //copy normal ascii range characters
|
||||||
|
temp_str[i] = state->dstar_src[i];
|
||||||
|
else if (state->dstar_src[i] == 0) break; //hit the terminator, so stop
|
||||||
|
else temp_str[i] = 0x5F; //unknown to underscore
|
||||||
|
}
|
||||||
|
sprintf (src_str, "%s", temp_str);
|
||||||
|
|
||||||
|
//same for tgt str
|
||||||
|
memset(temp_str, 0, sizeof(temp_str));
|
||||||
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if (state->dstar_dst[i] == 0x20) //spaces to underscore
|
||||||
|
temp_str[i] = 0x5F;
|
||||||
|
else if (state->dstar_dst[i] > 0x20 && state->dstar_dst[i] < 0x7F) //copy normal ascii range characters
|
||||||
|
temp_str[i] = state->dstar_dst[i];
|
||||||
|
else if (state->dstar_dst[i] == 0) break; //hit the terminator, so stop
|
||||||
|
else temp_str[i] = 0x5F; //unknown to underscore
|
||||||
|
}
|
||||||
|
sprintf (tgt_str, "%s", temp_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
for (uint8_t i = 0; i < 20; i++)
|
||||||
|
source_id += state->dpmr_caller_id[i]; //convert to sum value to make a distinct enough src value
|
||||||
|
|
||||||
|
//need a strncmp here for 8 spaces in this field first so we don't blip a blank into the event history
|
||||||
|
if (strncmp(state->dpmr_caller_id, " ", 6) == 0)
|
||||||
|
source_id = 0;
|
||||||
|
|
||||||
|
sprintf (sysid_string, "DPMR_CC_%d", state->dpmr_color_code);
|
||||||
|
|
||||||
|
sprintf (src_str, "%s", state->dpmr_caller_id);
|
||||||
|
sprintf (tgt_str, "%s", state->dpmr_target_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||||||
|
{
|
||||||
|
source_id = 0;
|
||||||
|
if (opts->p25_is_tuned == 1)
|
||||||
|
{
|
||||||
|
source_id = state->lastsrc;
|
||||||
|
channel = state->edacs_tuned_lcn;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_id1 = state->edacs_site_id;
|
||||||
|
sys_id2 = state->edacs_area_code;
|
||||||
|
sys_id3 = state->edacs_sys_id;
|
||||||
|
svc_opts = state->edacs_vc_call_type;
|
||||||
|
char sup_str[200]; memset (sup_str, 0, sizeof(sup_str));
|
||||||
|
sprintf (sup_str, "%s", "_");
|
||||||
|
if (svc_opts & 0x02)
|
||||||
|
strcat (sup_str, "Digital_");
|
||||||
|
else strcat (sup_str, "Analog_");
|
||||||
|
if (svc_opts & 0x04)
|
||||||
|
strcat (sup_str, "Emergency_");
|
||||||
|
if (svc_opts & 0x08)
|
||||||
|
strcat (sup_str, "Group_");
|
||||||
|
if (svc_opts & 0x10)
|
||||||
|
strcat (sup_str, "I_");
|
||||||
|
if (svc_opts & 0x20)
|
||||||
|
strcat (sup_str, "ALL_");
|
||||||
|
if (svc_opts & 0x40)
|
||||||
|
strcat (sup_str, "INTER_");
|
||||||
|
if (svc_opts & 0x80)
|
||||||
|
strcat (sup_str, "TEST_");
|
||||||
|
if (svc_opts & 0x100)
|
||||||
|
strcat (sup_str, "AGENCY_");
|
||||||
|
if (svc_opts & 0x200)
|
||||||
|
strcat (sup_str, "FLEET_");
|
||||||
|
if (svc_opts & 0x01)
|
||||||
|
strcat (sup_str, "Voice_");
|
||||||
|
strcat (sup_str, "Call");
|
||||||
|
|
||||||
|
sprintf (sysid_string, "EDACS_SITE_%03d", sys_id1);
|
||||||
|
strcat (sysid_string, sup_str);
|
||||||
|
|
||||||
|
if (state->ea_mode == 0)
|
||||||
|
{
|
||||||
|
int afs = state->lasttg;
|
||||||
|
sprintf(src_str, "%s", ""); sprintf(tgt_str, "%s", "");
|
||||||
|
int a = (afs >> state->edacs_a_shift) & state->edacs_a_mask;
|
||||||
|
int f = (afs >> state->edacs_f_shift) & state->edacs_f_mask;
|
||||||
|
int s = afs & state->edacs_s_mask;
|
||||||
|
sprintf (tgt_str, "%03d_AFS_%02d_%02d%01d", afs, a, f, s);
|
||||||
|
if (state->lastsrc != 0x800 && state->lastsrc != 0)
|
||||||
|
sprintf (src_str, "LID_%d", state->lastsrc);
|
||||||
|
else sprintf (src_str, "LID_UNK");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we have a group_array import, search and load it here
|
||||||
|
//will search and load both target values, and src values if available
|
||||||
|
uint8_t t_name_loaded = 0;
|
||||||
|
uint8_t s_name_loaded = 0;
|
||||||
|
if (target_id != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < state->group_tally; i++)
|
||||||
|
{
|
||||||
|
if (state->group_array[i].groupNumber == target_id)
|
||||||
|
{
|
||||||
|
sprintf (t_name, "%s", state->group_array[i].groupName);
|
||||||
|
sprintf (t_mode, "%s", state->group_array[i].groupMode);
|
||||||
|
t_name_loaded = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_id != 0) //&& state->gi[slot] == 1
|
||||||
|
{
|
||||||
|
for (int i = 0; i < state->group_tally; i++)
|
||||||
|
{
|
||||||
|
if (state->group_array[i].groupNumber == source_id)
|
||||||
|
{
|
||||||
|
sprintf (s_name, "%s", state->group_array[i].groupName);
|
||||||
|
sprintf (s_mode, "%s", state->group_array[i].groupMode);
|
||||||
|
s_name_loaded = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//system type string (P25, DMR, etc)
|
||||||
|
const char * sys_string = "Digital";
|
||||||
|
if (state->lastsynctype != -1)
|
||||||
|
sys_string = SyncTypes[state->lastsynctype];
|
||||||
|
|
||||||
|
//date and time strings
|
||||||
|
char * timestr = getTimeN(time(NULL));
|
||||||
|
char * datestr = getDateN(time(NULL));
|
||||||
|
|
||||||
|
if (source_id != 0)
|
||||||
|
{
|
||||||
|
event_struct->Event_History_Items[0].write = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].color_pair = color_pair;
|
||||||
|
if (state->lastsynctype != -1)
|
||||||
|
event_struct->Event_History_Items[0].systype = state->lastsynctype;
|
||||||
|
else event_struct->Event_History_Items[0].systype = 39; //generic digital call
|
||||||
|
event_struct->Event_History_Items[0].subtype = subtype; //voice
|
||||||
|
event_struct->Event_History_Items[0].gi = state->gi[slot]; //need this add this to link control messages
|
||||||
|
event_struct->Event_History_Items[0].sys_id1 = sys_id1;
|
||||||
|
event_struct->Event_History_Items[0].sys_id2 = sys_id2;
|
||||||
|
event_struct->Event_History_Items[0].sys_id3 = sys_id3;
|
||||||
|
event_struct->Event_History_Items[0].sys_id4 = sys_id4;
|
||||||
|
event_struct->Event_History_Items[0].sys_id5 = sys_id5;
|
||||||
|
event_struct->Event_History_Items[0].enc = enc;
|
||||||
|
event_struct->Event_History_Items[0].enc_alg = alg_id;
|
||||||
|
event_struct->Event_History_Items[0].enc_key = key_id;
|
||||||
|
event_struct->Event_History_Items[0].mi = mi;
|
||||||
|
event_struct->Event_History_Items[0].svc = svc_opts;
|
||||||
|
event_struct->Event_History_Items[0].source_id = source_id;
|
||||||
|
event_struct->Event_History_Items[0].target_id = target_id;
|
||||||
|
event_struct->Event_History_Items[0].channel = channel; //need to add this to trunking messages, if tuned from call grant
|
||||||
|
if (opts->playfiles == 0) //if playing back .mbe files with a time in it, don't set this
|
||||||
|
event_struct->Event_History_Items[0].event_time = time(NULL);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].sysid_string, "%s", sysid_string);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].src_str, "%s", src_str);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].tgt_str, "%s", tgt_str);
|
||||||
|
|
||||||
|
sprintf (event_struct->Event_History_Items[0].t_name, "%s", t_name);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].s_name, "%s", s_name);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].t_mode, "%s", t_mode);
|
||||||
|
sprintf (event_struct->Event_History_Items[0].s_mode, "%s", s_mode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Craft an event string for ncurses event history, and a more complex string for logging
|
||||||
|
char event_string[2000]; memset(event_string, 0, sizeof(event_string));
|
||||||
|
|
||||||
|
//WIP: Seperate Voice Call Event Strings when SRC/TGT values are numerical,
|
||||||
|
//and a seperate one for when they are string values (M17, YSF, DSTAR, and dPMR, or use special formatting)
|
||||||
|
if (state->lastsynctype == 30 || state->lastsynctype == 31) //YSF Fusion //TODO: Data calls dumping a lot of events as VOICE
|
||||||
|
{
|
||||||
|
//TODO: See if we can add some decoded data as well in the future to an event string
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %s SRC: %s ", datestr, timestr, sys_string, state->ysf_tgt, state->ysf_src);
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 16 || state->lastsynctype == 17) //M17
|
||||||
|
{
|
||||||
|
//TODO: See if we can add some decoded data as well in the future to an event string
|
||||||
|
if (state->m17_dst == 0xFFFFFFFFFFFF)
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %s SRC: %s CAN: %02d;", datestr, timestr, sys_string, "BROADCAST", state->m17_src_str, state->m17_can);
|
||||||
|
else
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %s SRC: %s CAN: %02d;", datestr, timestr, sys_string, state->m17_dst_str, state->m17_src_str, state->m17_can);
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 6 || state->lastsynctype == 7 || state->lastsynctype == 18 || state->lastsynctype == 19) //DSTAR
|
||||||
|
{
|
||||||
|
//TODO: See if we can add some decoded data as well in the future to an event string
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %s SRC: %s ", datestr, timestr, sys_string, state->dstar_dst, state->dstar_src);
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 20 || state->lastsynctype == 24 || state->lastsynctype == 21 || state->lastsynctype == 25 || state->lastsynctype == 22 || state->lastsynctype == 26 || state->lastsynctype == 23 || state->lastsynctype == 27) //dPMR
|
||||||
|
{
|
||||||
|
//TODO: See if we can add some decoded data as well in the future to an event string
|
||||||
|
sprintf (event_string, "%s %s %s CC: %02d; TGT: %s; SRC: %s; ", datestr, timestr, sys_string, state->dpmr_color_code, state->dpmr_target_id, state->dpmr_caller_id);
|
||||||
|
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
|
||||||
|
strcat (event_string, "Scrambler Enc; ");
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 14 || state->lastsynctype == 15 || state->lastsynctype == 37 || state->lastsynctype == 38) //EDACS Calls
|
||||||
|
{
|
||||||
|
svc_opts = state->edacs_vc_call_type;
|
||||||
|
char sup_str[200]; memset (sup_str, 0, sizeof(sup_str));
|
||||||
|
sprintf (sup_str, "%s", "");
|
||||||
|
if (svc_opts & 0x02)
|
||||||
|
strcat (sup_str, "Digital ");
|
||||||
|
else strcat (sup_str, "Analog ");
|
||||||
|
if (svc_opts & 0x04)
|
||||||
|
strcat (sup_str, "Emergency ");
|
||||||
|
if (svc_opts & 0x08)
|
||||||
|
strcat (sup_str, "Group ");
|
||||||
|
if (svc_opts & 0x10)
|
||||||
|
strcat (sup_str, "I ");
|
||||||
|
if (svc_opts & 0x20)
|
||||||
|
strcat (sup_str, "ALL ");
|
||||||
|
if (svc_opts & 0x40)
|
||||||
|
strcat (sup_str, "INTER ");
|
||||||
|
if (svc_opts & 0x80)
|
||||||
|
strcat (sup_str, "TEST ");
|
||||||
|
if (svc_opts & 0x100)
|
||||||
|
strcat (sup_str, "AGENCY ");
|
||||||
|
if (svc_opts & 0x200)
|
||||||
|
strcat (sup_str, "FLEET ");
|
||||||
|
if (svc_opts & 0x01)
|
||||||
|
strcat (sup_str, "Voice ");
|
||||||
|
strcat (sup_str, "Call");
|
||||||
|
|
||||||
|
if (state->ea_mode == 1)
|
||||||
|
{
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %07d; SRC: %07d; LCN: %02d; SITE: %d:%d.%04X; %s; ", datestr, timestr, sys_string, target_id, source_id, channel, sys_id1, sys_id2, sys_id3, sup_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int afs = state->lasttg;
|
||||||
|
int a = (afs >> state->edacs_a_shift) & state->edacs_a_mask;
|
||||||
|
int f = (afs >> state->edacs_f_shift) & state->edacs_f_mask;
|
||||||
|
int s = afs & state->edacs_s_mask;
|
||||||
|
char afs_str[8];
|
||||||
|
getAfsString(state, afs_str, a, f, s);
|
||||||
|
char lid_str[20]; memset(lid_str, 0, sizeof(lid_str));
|
||||||
|
sprintf(lid_str, "%s", "");
|
||||||
|
if (state->lastsrc != 0 && state->lastsrc != 0x800)
|
||||||
|
sprintf (lid_str, "LID: %05d;", state->lastsrc);
|
||||||
|
else sprintf (lid_str, "LID: __UNK;");
|
||||||
|
|
||||||
|
sprintf (event_string, "%s %s %s AFS: %s (%04d); %s LCN: %02d; Site: %d; %s; ", datestr, timestr, sys_string, afs_str, afs, lid_str, channel, sys_id1, sup_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 10 || state->lastsynctype == 11 || state->lastsynctype == 12 || state->lastsynctype == 13 ||
|
||||||
|
state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34 ) //DMR
|
||||||
|
{
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; CC: %02d; SYS: %X; ", datestr, timestr, sys_string, target_id, source_id, sys_id2, sys_id1);
|
||||||
|
else
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; CC: %02d; ", datestr, timestr, sys_string, target_id, source_id, sys_id2);
|
||||||
|
if (enc)
|
||||||
|
strcat(event_string, "ENC; ");
|
||||||
|
if (alg_id != 0)
|
||||||
|
{
|
||||||
|
char ess_str[30];
|
||||||
|
sprintf (ess_str, "ALG: %02X; KID: %02X; ", alg_id, key_id);
|
||||||
|
strcat(event_string, ess_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
//monitor for misc link control that may set a SO without having SO inside of it,
|
||||||
|
//those could cause misc issues here, will need to observe and make adjustments
|
||||||
|
if (svc_opts & 0x80)
|
||||||
|
strcat (event_string, "Emergency; ");
|
||||||
|
|
||||||
|
if (svc_opts & 0x08)
|
||||||
|
strcat (event_string, "Broadcast; ");
|
||||||
|
|
||||||
|
if (svc_opts & 0x04)
|
||||||
|
strcat (event_string, "OVCM; ");
|
||||||
|
|
||||||
|
if (state->gi[slot] == 0)
|
||||||
|
strcat (event_string, "Group; ");
|
||||||
|
else if (state->gi[slot] == 1)
|
||||||
|
strcat (event_string, "Private; ");
|
||||||
|
|
||||||
|
if (mfid == 0x10)
|
||||||
|
{
|
||||||
|
if (svc_opts & 0x20)
|
||||||
|
strcat (event_string, "TXI; ");
|
||||||
|
else if (svc_opts & 0x10)
|
||||||
|
strcat (event_string, "TXI; "); //this is the svc opt bit that tells you when the next VC6 will be pre-empted, but not helpful here
|
||||||
|
|
||||||
|
if (svc_opts & 0x03)
|
||||||
|
strcat (event_string, "PRIORITY; "); //need to break this apart into each one, but need to double check the decoded value is accurate
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (state->lastsynctype == 0 || state->lastsynctype == 1 || state->lastsynctype == 35 || state->lastsynctype == 36)
|
||||||
|
{
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; NAC: %03X; NET_STS: %05X:%03X:%d.%d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3, sys_id1, sys_id2, sys_id4, sys_id5);
|
||||||
|
else
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; NAC: %03X; ", datestr, timestr, sys_string, target_id, source_id, sys_id3);
|
||||||
|
if (alg_id != 0 && alg_id != 0x80)
|
||||||
|
{
|
||||||
|
char ess_str[30];
|
||||||
|
sprintf (ess_str, "ENC; ALG: %02X; KID: %04X; ", alg_id, key_id);
|
||||||
|
strcat(event_string, ess_str);
|
||||||
|
}
|
||||||
|
if (svc_opts & 0x80)
|
||||||
|
strcat (event_string, "Emergency; ");
|
||||||
|
if (state->gi[slot] == 0)
|
||||||
|
strcat (event_string, "Group; ");
|
||||||
|
else if (state->gi[slot] == 1)
|
||||||
|
strcat (event_string, "Private; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (state->lastsynctype == 28 || state->lastsynctype == 29)
|
||||||
|
{
|
||||||
|
if (sys_id1)
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; RAN: %02d; SYS: %d.%d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3, sys_id2, sys_id1);
|
||||||
|
else
|
||||||
|
sprintf (event_string, "%s %s %s TGT: %08d; SRC: %08d; RAN: %02d; ", datestr, timestr, sys_string, target_id, source_id, sys_id3);
|
||||||
|
if (enc)
|
||||||
|
strcat(event_string, "ENC; ");
|
||||||
|
if (alg_id != 0)
|
||||||
|
{
|
||||||
|
char ess_str[30];
|
||||||
|
sprintf (ess_str, "ALG: %d; KID: %02X; ", alg_id, key_id);
|
||||||
|
strcat(event_string, ess_str);
|
||||||
|
}
|
||||||
|
if (state->gi[slot] == 0)
|
||||||
|
strcat (event_string, "Group; ");
|
||||||
|
else if (state->gi[slot] == 1)
|
||||||
|
strcat (event_string, "Private; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_name_loaded)
|
||||||
|
{
|
||||||
|
char group[420];
|
||||||
|
sprintf (group, "TName: %s; Mode: %s; ", t_name, t_mode);
|
||||||
|
strcat (event_string, group);
|
||||||
|
}
|
||||||
|
if (s_name_loaded)
|
||||||
|
{
|
||||||
|
char private[420];
|
||||||
|
sprintf (private, "SName: %s; Mode: %s; ", s_name, s_mode);
|
||||||
|
strcat (event_string, private);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf (event_struct->Event_History_Items[0].event_string, "%s", event_string);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void watchdog_event_datacall (dsd_opts * opts, dsd_state * state, uint32_t src, uint32_t dst, char * data_string, uint8_t slot)
|
||||||
|
{
|
||||||
|
UNUSED(opts);
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].write = 0;
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].color_pair == 4) //if not set previously by specific decoder //don't touch this one
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].color_pair = 4; //default data color //you can change this one
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].systype = state->lastsynctype;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].subtype = 6; //data
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].gi = state->gi[slot];
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].enc = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].enc_alg = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].enc_key = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].mi = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].svc = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].source_id = src;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].target_id = dst;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].channel = 0;
|
||||||
|
state->event_history_s[slot].Event_History_Items[0].event_time = time(NULL);
|
||||||
|
|
||||||
|
//date and time strings //getTimeN(time(NULL)); //getDateN(time(NULL));
|
||||||
|
char * timestr = getTimeN(time(NULL));
|
||||||
|
char * datestr = getDateN(time(NULL));
|
||||||
|
|
||||||
|
char event_string[2000]; memset (event_string, 0, sizeof(event_string));
|
||||||
|
sprintf (event_string, "%s %s ", datestr, timestr);
|
||||||
|
strcat (event_string, data_string); //may need to check for potential overflow of this
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].event_string, "%s", event_string); //could change this to a strncpy to prevent potential overflow
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//call alert on data calls
|
||||||
|
if (opts->call_alert)
|
||||||
|
beeper (opts, state, slot, 80, 20, 3);
|
||||||
|
}
|
||||||
1516
src/dsd_file.c
1516
src/dsd_file.c
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,41 @@
|
|||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
|
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
|
||||||
#define M17ZEROS 80 //ONLY SEE 79 THOUGH
|
#define M17ZEROS 80
|
||||||
float m17gain = 10.0f;
|
float m17gain = 3.16227766f; //sqrt of 10.0f
|
||||||
static float m17xv[M17ZEROS+1];
|
static float m17xv[81];
|
||||||
float m17coeffs[81] =
|
|
||||||
|
//sample RRC filter for 48kHz sample rate
|
||||||
|
//alpha=0.5, span=8, sps=10, gain=sqrt(sps)
|
||||||
|
float m17coeffs[81] = //replaced old ones with ones from libm17
|
||||||
{
|
{
|
||||||
-0.009265784007800534, -0.006136551625729697, -0.001125978562075172, 0.004891777252042491,
|
-0.003195702904062073f, -0.002930279157647190f, -0.001940667871554463f,
|
||||||
0.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299,
|
-0.000356087678023658f, 0.001547011339077758f, 0.003389554791179751f,
|
||||||
0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372,
|
0.004761898604225673f, 0.005310860846138910f, 0.004824746306020221f,
|
||||||
-0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935,
|
0.003297923526848786f, 0.000958710871218619f, -0.001749908029791816f,
|
||||||
0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876,
|
-0.004238694106631223f, -0.005881783042101693f, -0.006150256456781309f,
|
||||||
0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165,
|
-0.004745376707651645f, -0.001704189656473565f, 0.002547854551539951f,
|
||||||
-0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576,
|
0.007215575568844704f, 0.011231038205363532f, 0.013421952197060707f,
|
||||||
-0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196,
|
0.012730475385624438f, 0.008449554307303753f, 0.000436744366018287f,
|
||||||
0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068,
|
-0.010735380379191660f, -0.023726883538258272f, -0.036498030780605324f,
|
||||||
0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815,
|
-0.046500883189991064f, -0.050979050575999614f, -0.047340680079891187f,
|
||||||
1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068,
|
-0.033554880492651755f, -0.008513823955725943f, 0.027696543159614194f,
|
||||||
0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196,
|
0.073664520037517042f, 0.126689053778116234f, 0.182990955139333916f,
|
||||||
-0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576,
|
0.238080025892859704f, 0.287235637987091563f, 0.326040247765297220f,
|
||||||
-0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165,
|
0.350895727088112619f, 0.359452932027607974f, 0.350895727088112619f,
|
||||||
0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876,
|
0.326040247765297220f, 0.287235637987091563f, 0.238080025892859704f,
|
||||||
0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935,
|
0.182990955139333916f, 0.126689053778116234f, 0.073664520037517042f,
|
||||||
-0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372,
|
0.027696543159614194f, -0.008513823955725943f, -0.033554880492651755f,
|
||||||
-0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299,
|
-0.047340680079891187f, -0.050979050575999614f, -0.046500883189991064f,
|
||||||
0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491,
|
-0.036498030780605324f, -0.023726883538258272f, -0.010735380379191660f,
|
||||||
-0.001125978562075172, -0.006136551625729697, -0.009265784007800534
|
0.000436744366018287f, 0.008449554307303753f, 0.012730475385624438f,
|
||||||
|
0.013421952197060707f, 0.011231038205363532f, 0.007215575568844704f,
|
||||||
|
0.002547854551539951f, -0.001704189656473565f, -0.004745376707651645f,
|
||||||
|
-0.006150256456781309f, -0.005881783042101693f, -0.004238694106631223f,
|
||||||
|
-0.001749908029791816f, 0.000958710871218619f, 0.003297923526848786f,
|
||||||
|
0.004824746306020221f, 0.005310860846138910f, 0.004761898604225673f,
|
||||||
|
0.003389554791179751f, 0.001547011339077758f, -0.000356087678023658f,
|
||||||
|
-0.001940667871554463f, -0.002930279157647190f, -0.003195702904062073f
|
||||||
};
|
};
|
||||||
|
|
||||||
// Original DMR filter
|
// Original DMR filter
|
||||||
@@ -245,3 +257,12 @@ dsd_input_filter(short sample, int mode)
|
|||||||
|
|
||||||
return (short)(sum / gain); // filtered sample out
|
return (short)(sum / gain); // filtered sample out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_rrc_filter_memory()
|
||||||
|
{
|
||||||
|
memset (m17xv, 0, 81*sizeof(float));
|
||||||
|
memset (xv, 0, 61*sizeof(float));
|
||||||
|
memset (dxv, 0, 61*sizeof(float));
|
||||||
|
memset (nxv, 0, 135*sizeof(float));
|
||||||
|
memset (dpmrxv, 0, 135*sizeof(float));
|
||||||
|
}
|
||||||
@@ -20,36 +20,27 @@
|
|||||||
#define NULL 0
|
#define NULL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "p25p1_check_nid.h"
|
|
||||||
|
|
||||||
void
|
void
|
||||||
printFrameInfo (dsd_opts * opts, dsd_state * state)
|
printFrameInfo (dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
|
|
||||||
int level;
|
UNUSED(opts);
|
||||||
|
|
||||||
level = (int) state->max / 164;
|
fprintf (stderr, "%s", KCYN);
|
||||||
if (opts->verbose > 0)
|
if (state->p2_wacn != 0)
|
||||||
{
|
fprintf (stderr, "WACN: %05llX; ", state->p2_wacn);
|
||||||
// fprintf (stderr,"inlvl: %2i%% ", level);
|
if (state->p2_sysid != 0)
|
||||||
UNUSED(level);
|
fprintf (stderr, "SYS: %03llX; ", state->p2_sysid);
|
||||||
}
|
if (state->p2_cc != 0)
|
||||||
if (state->nac != 0)
|
fprintf (stderr, "NAC/CC: %03llX; ", state->p2_cc);
|
||||||
{
|
else fprintf (stderr, "NAC: %03X; ", state->nac);
|
||||||
fprintf (stderr, "%s", KCYN);
|
|
||||||
fprintf (stderr,"nac: [%4X] ", state->nac);
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts->verbose > 1)
|
if (state->p2_rfssid != 0)
|
||||||
{
|
fprintf (stderr, "RFSS: %03lld; ", state->p2_rfssid);
|
||||||
fprintf (stderr, "%s", KGRN);
|
if (state->p2_siteid != 0)
|
||||||
fprintf (stderr,"src: [%8i] ", state->lastsrc);
|
fprintf (stderr, "Site: %03lld; ", state->p2_siteid);
|
||||||
fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
|
||||||
fprintf (stderr, "%s", KGRN);
|
|
||||||
fprintf (stderr,"tg: [%5i] ", state->lasttg);
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -113,7 +104,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Start DMR Types
|
//Start DMR Types
|
||||||
else if ((state->synctype >= 10) && (state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC
|
else if ((state->synctype >= 10 && state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC
|
||||||
{
|
{
|
||||||
|
|
||||||
//print manufacturer strings to branding, disabled 0x10 moto other systems can use that fid set
|
//print manufacturer strings to branding, disabled 0x10 moto other systems can use that fid set
|
||||||
@@ -269,15 +260,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
|||||||
processYSF(opts, state);
|
processYSF(opts, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//M17
|
//M17 STR
|
||||||
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (state->synctype == 99) || (state->synctype == 98))
|
else if (state->synctype == 16)
|
||||||
{
|
{
|
||||||
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
processM17STR(opts, state);
|
||||||
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
|
||||||
else if (state->synctype == 16 || state->synctype == 17)
|
|
||||||
processM17STR(opts, state);
|
|
||||||
else
|
|
||||||
processM17LSF(opts, state);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//P25 P2
|
//P25 P2
|
||||||
|
|||||||
@@ -18,59 +18,33 @@
|
|||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
|
||||||
{
|
|
||||||
time_t t = time(NULL);
|
|
||||||
|
|
||||||
char * curr;
|
|
||||||
char * stamp = asctime(localtime( & t));
|
|
||||||
|
|
||||||
curr = strtok(stamp, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
curr = strtok(NULL, " ");
|
|
||||||
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * getDate(void) {
|
|
||||||
#ifdef AERO_BUILD
|
|
||||||
char datename[80];
|
|
||||||
#else
|
|
||||||
char datename[99];
|
|
||||||
#endif
|
|
||||||
char * curr2;
|
|
||||||
struct tm * to;
|
|
||||||
time_t t;
|
|
||||||
t = time(NULL);
|
|
||||||
to = localtime( & t);
|
|
||||||
strftime(datename, sizeof(datename), "%Y-%m-%d", to);
|
|
||||||
curr2 = strtok(datename, " ");
|
|
||||||
return curr2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
||||||
{
|
{
|
||||||
UNUSED3(state, offset, modulation);
|
UNUSED3(state, offset, modulation);
|
||||||
|
|
||||||
|
char * timestr = getTimeC();
|
||||||
if (opts->verbose > 0)
|
if (opts->verbose > 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr,"%s ", getTime());
|
fprintf (stderr,"%s ", timestr);
|
||||||
fprintf (stderr,"Sync: %s ", frametype);
|
fprintf (stderr,"Sync: %s ", frametype);
|
||||||
}
|
}
|
||||||
if (opts->verbose > 2)
|
|
||||||
{
|
//oops, that made a nested if-if-if-if statement,
|
||||||
//fprintf (stderr,"o: %4i ", offset);
|
//causing a memory leak
|
||||||
}
|
|
||||||
if (opts->verbose > 1)
|
// if (opts->verbose > 2)
|
||||||
{
|
//fprintf (stderr,"o: %4i ", offset);
|
||||||
//fprintf (stderr,"mod: %s ", modulation);
|
// if (opts->verbose > 1)
|
||||||
}
|
//fprintf (stderr,"mod: %s ", modulation);
|
||||||
if (opts->verbose > 2)
|
// if (opts->verbose > 2)
|
||||||
{
|
//fprintf (stderr,"g: %f ", state->aout_gain);
|
||||||
//fprintf (stderr,"g: %f ", state->aout_gain);
|
|
||||||
}
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,21 +158,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
char synctest[25];
|
char synctest[25];
|
||||||
char synctest12[13]; //dPMR
|
char synctest12[13]; //dPMR
|
||||||
char synctest10[11]; //NXDN FSW only
|
char synctest10[11]; //NXDN FSW only
|
||||||
char synctest18[19];
|
|
||||||
char synctest32[33];
|
char synctest32[33];
|
||||||
char synctest20[21]; //YSF
|
char synctest20[21]; //YSF
|
||||||
char synctest21[22]; //P25 S-OEMI (SACCH)
|
|
||||||
char synctest48[49]; //EDACS
|
char synctest48[49]; //EDACS
|
||||||
char synctest8[9]; //M17
|
char synctest8[9]; //M17
|
||||||
char synctest16[17]; //M17 Preamble
|
|
||||||
char modulation[8];
|
char modulation[8];
|
||||||
char *synctest_p;
|
char *synctest_p;
|
||||||
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
||||||
int lmin, lmax, lidx;
|
int lmin, lmax, lidx;
|
||||||
UNUSED2(synctest18, synctest21);
|
|
||||||
|
|
||||||
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
//assign t_max value based on decoding type expected (all non-auto decodes first)
|
||||||
int t_max; //maximum values allowed for t will depend on decoding type - NXDN will be 10, others will be more
|
int t_max = 24; //initialize as an actual value to prevent any overflow related issues
|
||||||
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1)
|
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1)
|
||||||
{
|
{
|
||||||
t_max = 10;
|
t_max = 10;
|
||||||
@@ -221,6 +191,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
{
|
{
|
||||||
t_max = 19; //Phase 2 S-ISCH is only 19
|
t_max = 19; //Phase 2 S-ISCH is only 19
|
||||||
}
|
}
|
||||||
|
else if (opts->analog_only == 1) //shim to make sure this is set to a reasonable value
|
||||||
|
{
|
||||||
|
t_max = 24;
|
||||||
|
}
|
||||||
else t_max = 24; //24 for everything else
|
else t_max = 24; //24 for everything else
|
||||||
|
|
||||||
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
|
||||||
@@ -233,11 +207,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
t = 0;
|
t = 0;
|
||||||
synctest10[10] = 0;
|
synctest10[10] = 0;
|
||||||
synctest[24] = 0;
|
synctest[24] = 0;
|
||||||
|
synctest8[8] = 0;
|
||||||
synctest12[12] = 0;
|
synctest12[12] = 0;
|
||||||
synctest18[18] = 0;
|
|
||||||
synctest48[48] = 0;
|
synctest48[48] = 0;
|
||||||
synctest32[32] = 0;
|
synctest32[32] = 0;
|
||||||
synctest20[20] = 0;
|
synctest20[20] = 0;
|
||||||
|
modulation[7] = 0; //not initialized or terminated (unsure if this would be an issue or not)
|
||||||
synctest_pos = 0;
|
synctest_pos = 0;
|
||||||
synctest_p = synctest_buf + 10;
|
synctest_p = synctest_buf + 10;
|
||||||
sync = 0;
|
sync = 0;
|
||||||
@@ -247,11 +222,17 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
lastt = 0;
|
lastt = 0;
|
||||||
state->numflips = 0;
|
state->numflips = 0;
|
||||||
|
|
||||||
//move ncursesPrinter outside of the sync loop, causes weird lag inside the loop
|
//run here as well
|
||||||
if (opts->use_ncurses_terminal == 1)
|
if (opts->use_ncurses_terminal == 1)
|
||||||
{
|
|
||||||
ncursesPrinter(opts, state);
|
ncursesPrinter(opts, state);
|
||||||
}
|
|
||||||
|
//slot 1
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
|
//slot 2 for TDMA systems
|
||||||
|
watchdog_event_history(opts, state, 1);
|
||||||
|
watchdog_event_current(opts, state, 1);
|
||||||
|
|
||||||
if ((opts->symboltiming == 1) && (state->carrier == 1))
|
if ((opts->symboltiming == 1) && (state->carrier == 1))
|
||||||
{
|
{
|
||||||
@@ -263,6 +244,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
|
|
||||||
t++;
|
t++;
|
||||||
|
|
||||||
|
//run ncurses printer more frequently when no sync to speed up responsiveness of it during no sync period
|
||||||
|
//NOTE: Need to monitor and test this, if responsiveness issues arise, then disable this
|
||||||
|
if ( opts->use_ncurses_terminal == 1 && ((t % 300) == 0)) //t maxes out at 1800 (6 times each getFrameSync)
|
||||||
|
ncursesPrinter(opts, state);
|
||||||
|
|
||||||
symbol = getSymbol (opts, state, 0);
|
symbol = getSymbol (opts, state, 0);
|
||||||
|
|
||||||
lbuf[lidx] = symbol;
|
lbuf[lidx] = symbol;
|
||||||
@@ -455,7 +441,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
sprintf (state->ftype, "P25 Phase 1");
|
sprintf (state->ftype, "P25 Phase 1");
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "+P25p1 ", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+P25p1", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
state->lastsynctype = 0;
|
state->lastsynctype = 0;
|
||||||
state->last_cc_sync_time = time(NULL);
|
state->last_cc_sync_time = time(NULL);
|
||||||
@@ -578,106 +564,24 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
}
|
}
|
||||||
//end YSF sync
|
//end YSF sync
|
||||||
|
|
||||||
//M17 Sync -- Just STR and LSF for now
|
//M17 Sync -- Just STR
|
||||||
strncpy(synctest16, (synctest_p - 15), 16);
|
|
||||||
strncpy(synctest8, (synctest_p - 7), 8);
|
strncpy(synctest8, (synctest_p - 7), 8);
|
||||||
if(opts->frame_m17 == 1)
|
if(opts->frame_m17 == 1)
|
||||||
{
|
{
|
||||||
//preambles will skip dibits in an attempt to prime the
|
if (strcmp(synctest8, M17_STR) == 0)
|
||||||
//demodulator but not attempt any decoding
|
|
||||||
if (strcmp(synctest8, M17_PRE) == 0)
|
|
||||||
{
|
{
|
||||||
if (opts->inverted_m17 == 0)
|
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
|
||||||
|
state->carrier = 1;
|
||||||
|
state->offset = synctest_pos;
|
||||||
|
state->max = ((state->max) + lmax) / 2;
|
||||||
|
state->min = ((state->min) + lmin) / 2;
|
||||||
|
if (state->lastsynctype == 16)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "+M17 PREAMBLE", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
state->lastsynctype = 98;
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
return (98);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(synctest8, M17_PIV) == 0)
|
|
||||||
{
|
|
||||||
if (opts->inverted_m17 == 1)
|
|
||||||
{
|
|
||||||
printFrameSync (opts, state, "-M17 PREAMBLE", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
state->lastsynctype = 99;
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
return (99);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(synctest8, M17_STR) == 0)
|
|
||||||
{
|
|
||||||
if (opts->inverted_m17 == 0)
|
|
||||||
{
|
|
||||||
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
if (state->lastsynctype == 16 || state->lastsynctype == 8)
|
|
||||||
{
|
|
||||||
state->lastsynctype = 16;
|
|
||||||
return (16);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 16;
|
state->lastsynctype = 16;
|
||||||
fprintf (stderr, "\n");
|
return (16);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printFrameSync (opts, state, "-M17 LSF", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
if (state->lastsynctype == 99)
|
|
||||||
{
|
|
||||||
state->lastsynctype = 9;
|
|
||||||
return (9);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 9;
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(synctest8, M17_LSF) == 0)
|
|
||||||
{
|
|
||||||
if (opts->inverted_m17 == 1)
|
|
||||||
{
|
|
||||||
printFrameSync (opts, state, "-M17 STR", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
if (state->lastsynctype == 17 || state->lastsynctype == 9)
|
|
||||||
{
|
|
||||||
state->lastsynctype = 17;
|
|
||||||
return (17);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 17;
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printFrameSync (opts, state, "+M17 LSF", synctest_pos + 1, modulation);
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
if (state->lastsynctype == 98)
|
|
||||||
{
|
|
||||||
state->lastsynctype = 8;
|
|
||||||
return (8);
|
|
||||||
}
|
|
||||||
state->lastsynctype = 8;
|
|
||||||
fprintf (stderr, "\n");
|
|
||||||
}
|
}
|
||||||
|
state->lastsynctype = 16;
|
||||||
|
fprintf (stderr, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//end M17
|
//end M17
|
||||||
@@ -698,13 +602,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
state->lastsynctype = 35; //35
|
state->lastsynctype = 35; //35
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "+P25p2 SISCH", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "+P25p2", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0)
|
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0)
|
||||||
{
|
{
|
||||||
//fprintf (stderr, "%s", KCYN);
|
printFrameInfo(opts, state);
|
||||||
fprintf (stderr, " WACN [%05llX] SYS [%03llX] NAC [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
|
||||||
//fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -731,13 +633,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
opts->inverted_p2 = 1;
|
opts->inverted_p2 = 1;
|
||||||
if (opts->errorbars == 1)
|
if (opts->errorbars == 1)
|
||||||
{
|
{
|
||||||
printFrameSync (opts, state, "-P25p2 SISCH", synctest_pos + 1, modulation);
|
printFrameSync (opts, state, "-P25p2", synctest_pos + 1, modulation);
|
||||||
}
|
}
|
||||||
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0)
|
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0)
|
||||||
{
|
{
|
||||||
//fprintf (stderr, "%s", KCYN);
|
printFrameInfo(opts, state);
|
||||||
fprintf (stderr, " WACN [%05llX] SYS [%03llX] NAC [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
|
|
||||||
//fprintf (stderr, "%s", KNRM);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -857,32 +757,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
|||||||
return (32);
|
return (32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//not sure if this should be here, RC data should only be present in vc6?
|
|
||||||
if(strcmp (synctest, DMR_RC_DATA_SYNC) == 0)
|
|
||||||
{
|
|
||||||
state->carrier = 1;
|
|
||||||
state->offset = synctest_pos;
|
|
||||||
state->max = ((state->max) + lmax) / 2;
|
|
||||||
state->min = ((state->min) + lmin) / 2;
|
|
||||||
//state->directmode = 0;
|
|
||||||
//fprintf (stderr, "DMR RC DATA\n");
|
|
||||||
state->dmr_ms_rc == 1; //set flag for RC data, then process accordingly and reset back to 0 afterwards
|
|
||||||
if (0 == 0) //opts->inverted_dmr
|
|
||||||
{
|
|
||||||
// voice frame
|
|
||||||
sprintf(state->ftype, "DMR RC");
|
|
||||||
if (opts->errorbars == 1)
|
|
||||||
{
|
|
||||||
//printFrameSync (opts, state, "+DMR RC Data", synctest_pos + 1, modulation);
|
|
||||||
}
|
|
||||||
if (state->lastsynctype != 34)
|
|
||||||
{
|
|
||||||
//state->firstframe = 1;
|
|
||||||
}
|
|
||||||
state->lastsynctype = 34;
|
|
||||||
return (34);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strcmp (synctest, DMR_MS_VOICE_SYNC) == 0)
|
if(strcmp (synctest, DMR_MS_VOICE_SYNC) == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
243
src/dsd_gps.c
243
src/dsd_gps.c
@@ -15,6 +15,12 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
|||||||
|
|
||||||
int slot = state->currentslot;
|
int slot = state->currentslot;
|
||||||
|
|
||||||
|
//May need to set this in the UDT header, or pass it into this function to be sure
|
||||||
|
// uint32_t src = 0;
|
||||||
|
// if (slot == 0)
|
||||||
|
// src = state->lastsrc;
|
||||||
|
// else src = state->lastsrcR;
|
||||||
|
|
||||||
//NOTE: This format is pretty much the same as DMR EMB GPS, but has a few extra elements,
|
//NOTE: This format is pretty much the same as DMR EMB GPS, but has a few extra elements,
|
||||||
//so I got lazy and just lifted most of the code from there, also assuming same lat/lon calcs
|
//so I got lazy and just lifted most of the code from there, also assuming same lat/lon calcs
|
||||||
//since those have been tested to work in DMR EMB GPS and units are same in LIP
|
//since those have been tested to work in DMR EMB GPS and units are same in LIP
|
||||||
@@ -89,7 +95,7 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
|||||||
int dt = (int)dir;
|
int dt = (int)dir;
|
||||||
|
|
||||||
//sanity check
|
//sanity check
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
if (fabs (latitude) < 90 && fabs(longitude) < 180)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Src(Hash); %03d; Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf); Spd: %d km/h; Dir: %d%s",add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude, vt, dt, deg_glyph);
|
fprintf (stderr, "Src(Hash); %03d; Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf); Spd: %d km/h; Dir: %d%s",add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude, vt, dt, deg_glyph);
|
||||||
|
|
||||||
@@ -115,14 +121,21 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
|||||||
}
|
}
|
||||||
else sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s Unknown Pos Err; Spd: %d km/h; Dir %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, vt, dt, deg_glyph);
|
else sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s Unknown Pos Err; Spd: %d km/h; Dir %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, vt, dt, deg_glyph);
|
||||||
|
|
||||||
|
//save to event history string
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * datestr = getDate();
|
||||||
|
char * timestr = getTime();
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
fprintf (pFile, "%s\t", timestr );
|
||||||
fprintf (pFile, "%08d\t", add_hash);
|
fprintf (pFile, "%08d\t", add_hash);
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
fprintf (pFile, "%.5lf\t", latitude);
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
fprintf (pFile, "%.5lf\t", longitude);
|
||||||
@@ -131,6 +144,17 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
|||||||
fprintf (pFile, "\n");
|
fprintf (pFile, "\n");
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -169,9 +193,9 @@ void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint
|
|||||||
uint8_t nmea_utc_hh = (uint8_t)ConvertBitIntoBytes(&input[66], 5);
|
uint8_t nmea_utc_hh = (uint8_t)ConvertBitIntoBytes(&input[66], 5);
|
||||||
uint8_t nmea_utc_mm = (uint8_t)ConvertBitIntoBytes(&input[71], 6);
|
uint8_t nmea_utc_mm = (uint8_t)ConvertBitIntoBytes(&input[71], 6);
|
||||||
//seconds and the addition of COG is the difference between short and long formats
|
//seconds and the addition of COG is the difference between short and long formats
|
||||||
uint8_t nmea_utc_ss3 = (uint8_t)ConvertBitIntoBytes(&input[77], 3); //seconds in 10s
|
uint8_t nmea_utc_ss3 = (uint8_t)ConvertBitIntoBytes(&input[77], 3) * 10; //seconds in 10s
|
||||||
uint8_t nmea_utc_ss6 = (uint8_t)ConvertBitIntoBytes(&input[77], 6); //seconds in 1s
|
uint8_t nmea_utc_ss6 = (uint8_t)ConvertBitIntoBytes(&input[77], 6); //seconds in 1s
|
||||||
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[103], 9); //course over ground in degrees
|
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[103], 9); //course over ground in degrees
|
||||||
|
|
||||||
//lat and lon conversion
|
//lat and lon conversion
|
||||||
char deg_glyph[4];
|
char deg_glyph[4];
|
||||||
@@ -215,18 +239,25 @@ void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint
|
|||||||
//save to ncurses string
|
//save to ncurses string
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
||||||
|
|
||||||
|
//save to event history string
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "(%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * datestr = getDate();
|
||||||
|
char * timestr = getTime();
|
||||||
|
|
||||||
int s = (int)fkph; //rounded interger format for the log report
|
int s = (int)fkph; //rounded interger format for the log report
|
||||||
int a = 0;
|
int a = 0;
|
||||||
if (type == 2)
|
if (type == 2)
|
||||||
a = nmea_cog; //long format only
|
a = nmea_cog; //long format only
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time if desired, but would require local user offset
|
fprintf (pFile, "%s\t", timestr ); //could switch to UTC time if desired, but would require local user offset
|
||||||
fprintf (pFile, "%08d\t", src);
|
fprintf (pFile, "%08d\t", src);
|
||||||
fprintf (pFile, "%.6lf\t", latitude);
|
fprintf (pFile, "%.6lf\t", latitude);
|
||||||
fprintf (pFile, "%.6lf\t", longitude);
|
fprintf (pFile, "%.6lf\t", longitude);
|
||||||
@@ -235,6 +266,17 @@ void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint
|
|||||||
fprintf (pFile, "\n");
|
fprintf (pFile, "\n");
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -303,16 +345,24 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t
|
|||||||
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
|
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
|
||||||
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
|
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
//is this from LCW, or MAC?
|
||||||
|
uint16_t header = (uint16_t)ConvertBitIntoBytes(&input[0], 16);
|
||||||
|
|
||||||
fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src);
|
fprintf (stderr, "\n");
|
||||||
|
if (header == 0x2AA4)
|
||||||
|
fprintf (stderr, " SRC: %08d;", src);
|
||||||
|
else
|
||||||
|
fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src);
|
||||||
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
|
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
|
||||||
|
|
||||||
//Speed in Knots (assuming in knots, and not in mps, or kph)
|
//Speed in Knots (assuming in knots, and not in mps, or kph)
|
||||||
if (nmea_speed > 126)
|
if (header != 0x2AA4) //can't yet verify this is present or accurate on LCW
|
||||||
fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S.
|
{
|
||||||
else
|
if (nmea_speed > 126)
|
||||||
fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph);
|
fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S.
|
||||||
|
else
|
||||||
|
fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph);
|
||||||
|
}
|
||||||
|
|
||||||
//Course Over Ground (COG)
|
//Course Over Ground (COG)
|
||||||
fprintf (stderr, " COG: %03d%s;", nmea_cog, deg_glyph); //%360
|
fprintf (stderr, " COG: %03d%s;", nmea_cog, deg_glyph); //%360
|
||||||
@@ -331,20 +381,28 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t
|
|||||||
else fprintf (stderr, " Last Fix;");
|
else fprintf (stderr, " Last Fix;");
|
||||||
|
|
||||||
//save to ncurses string
|
//save to ncurses string
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
sprintf (state->dmr_embedded_gps[slot], "(%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
|
||||||
|
|
||||||
|
//save to event history string
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == src && src != 0)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * datestr = getDate();
|
||||||
|
char * timestr = getTime();
|
||||||
|
|
||||||
//rounded interger formats for the log report
|
//rounded interger formats for the log report
|
||||||
int s = (int)fkph;
|
int s = (int)fkph;
|
||||||
int a = nmea_cog;
|
int a = nmea_cog;
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time on PDU if desired
|
fprintf (pFile, "%s\t", timestr ); //could switch to UTC time on PDU if desired
|
||||||
fprintf (pFile, "%08d\t", src);
|
fprintf (pFile, "%08d\t", src);
|
||||||
fprintf (pFile, "%.6lf\t", latitude);
|
fprintf (pFile, "%.6lf\t", latitude);
|
||||||
fprintf (pFile, "%.6lf\t", longitude);
|
fprintf (pFile, "%.6lf\t", longitude);
|
||||||
@@ -353,6 +411,17 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t
|
|||||||
fprintf (pFile, "\n");
|
fprintf (pFile, "\n");
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: There seems to be a few more octets left undecoded in this PDU
|
//NOTE: There seems to be a few more octets left undecoded in this PDU
|
||||||
@@ -464,10 +533,14 @@ void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
|
|||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
char * datestr = getDate();
|
||||||
|
char * timestr = getTime();
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
fprintf (pFile, "%s\t", timestr );
|
||||||
fprintf (pFile, "%08d\t", src);
|
fprintf (pFile, "%08d\t", src);
|
||||||
fprintf (pFile, "%.6lf\t", lat_dec);
|
fprintf (pFile, "%.6lf\t", lat_dec);
|
||||||
fprintf (pFile, "%.6lf\t", lon_dec);
|
fprintf (pFile, "%.6lf\t", lon_dec);
|
||||||
@@ -476,6 +549,17 @@ void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
|
|||||||
fprintf (pFile, "\n");
|
fprintf (pFile, "\n");
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: Thanks to DSheirer (SDRTrunk) for helping me work out a few of the things in here
|
//NOTE: Thanks to DSheirer (SDRTrunk) for helping me work out a few of the things in here
|
||||||
@@ -541,7 +625,7 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
longitude = ((double)lon * lon_unit);
|
longitude = ((double)lon * lon_unit);
|
||||||
|
|
||||||
//sanity check
|
//sanity check
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
if (fabs(latitude) < 90 && fabs(longitude) < 180)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf)", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude);
|
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf)", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude);
|
||||||
|
|
||||||
@@ -557,18 +641,26 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
}
|
}
|
||||||
else sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Unknown Pos Err", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr);
|
else sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Unknown Pos Err", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr);
|
||||||
|
|
||||||
|
uint32_t src = 0;
|
||||||
|
if (slot == 0) src = state->lasttg;
|
||||||
|
if (slot == 1) src = state->lasttgR;
|
||||||
|
|
||||||
|
//save to event history string
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == src)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
int src = 0;
|
|
||||||
if (slot == 0) src = state->lasttg;
|
char * datestr = getDate();
|
||||||
if (slot == 1) src = state->lasttgR;
|
char * timestr = getTime();
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
fprintf (pFile, "%s\t", timestr );
|
||||||
fprintf (pFile, "%08d\t", src);
|
fprintf (pFile, "%08d\t", src);
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
fprintf (pFile, "%.5lf\t", latitude);
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
fprintf (pFile, "%.5lf\t", longitude);
|
||||||
@@ -584,8 +676,8 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//This Function has been redone and variables fixed to mirror SDRTrunk
|
//This Function needs testing, is tested working for NW and NE lat and
|
||||||
//my earlier assumption that this was the same format as DMR Embedded GPS was incorrect
|
//long coordinates, but not for SE and SW coordinates
|
||||||
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -604,18 +696,16 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
|
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
|
||||||
uint32_t lat_sign = lc_bits[24];
|
uint32_t lat_sign = lc_bits[24];
|
||||||
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[25], 23);
|
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[25], 23);
|
||||||
//todo: acquire more samples for additional validation
|
|
||||||
double lat_unit = 90.0f / 0x7FFFFF;
|
double lat_unit = 90.0f / 0x7FFFFF;
|
||||||
double lon_unit = 180.0f / 0x7FFFFF;
|
double lon_unit = 180.0f / 0x7FFFFF;
|
||||||
double lon_sf = 1.0f; //float value we can multiple longitude with
|
|
||||||
double lat_sf = 1.0f; //float value we can multiple latitude with
|
|
||||||
|
|
||||||
char latstr[3];
|
char latstr[3];
|
||||||
char lonstr[3];
|
char lonstr[3];
|
||||||
char valid[9];
|
char valid[12];
|
||||||
sprintf (latstr, "%s", "N");
|
sprintf (latstr, "%s", "N");
|
||||||
sprintf (lonstr, "%s", "E");
|
sprintf (lonstr, "%s", "E");
|
||||||
sprintf (valid, "%s", "Current");
|
sprintf (valid, "%s", "Current Fix");
|
||||||
|
|
||||||
double latitude = 0;
|
double latitude = 0;
|
||||||
double longitude = 0;
|
double longitude = 0;
|
||||||
@@ -623,32 +713,33 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
if (pf) fprintf (stderr, " Protected");
|
if (pf) fprintf (stderr, " Protected");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
latitude = ((double)lat * lat_unit);
|
||||||
if (lat_sign)
|
if (lat_sign)
|
||||||
{
|
{
|
||||||
|
latitude -= 90.0f;
|
||||||
sprintf (latstr, "%s", "S");
|
sprintf (latstr, "%s", "S");
|
||||||
lat_sf = -1.0f;
|
|
||||||
}
|
}
|
||||||
latitude = ((double)lat * lat_unit);
|
|
||||||
|
|
||||||
|
longitude = ((double)lon * lon_unit);
|
||||||
if (lon_sign)
|
if (lon_sign)
|
||||||
{
|
{
|
||||||
|
longitude -= 180.0f;
|
||||||
sprintf (lonstr, "%s", "W");
|
sprintf (lonstr, "%s", "W");
|
||||||
lon_sf = -1.0f;
|
|
||||||
}
|
}
|
||||||
longitude = ((double)lon * lon_unit);
|
|
||||||
|
|
||||||
//sanity check
|
//sanity check
|
||||||
if (abs (latitude) < 90 && abs(longitude) < 180)
|
if (fabs ((float)latitude) < 90 && fabs((float)longitude) < 180)
|
||||||
{
|
{
|
||||||
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf) ", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude * lat_sf, longitude * lon_sf);
|
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf) ", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude, longitude);
|
||||||
|
|
||||||
if (expired)
|
if (expired)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "Expired; ");
|
fprintf (stderr, "Last Fix; ");
|
||||||
sprintf (valid, "%s", "Expired");
|
sprintf (valid, "%s", "Last Fix");
|
||||||
}
|
}
|
||||||
else if (!expired)
|
else if (!expired)
|
||||||
fprintf (stderr, "Current; ");
|
fprintf (stderr, "Current Fix; ");
|
||||||
|
|
||||||
if (res_a)
|
if (res_a)
|
||||||
fprintf (stderr, "RES_A: %d; ", res_a);
|
fprintf (stderr, "RES_A: %d; ", res_a);
|
||||||
@@ -656,21 +747,28 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
if (res_b)
|
if (res_b)
|
||||||
fprintf (stderr, "RES_B: %02X; ", res_b);
|
fprintf (stderr, "RES_B: %02X; ", res_b);
|
||||||
|
|
||||||
|
uint32_t src = 0;
|
||||||
|
if (slot == 0) src = state->lastsrc;
|
||||||
|
if (slot == 1) src = state->lastsrcR;
|
||||||
|
|
||||||
//save to array for ncurses
|
//save to array for ncurses
|
||||||
sprintf (state->dmr_embedded_gps[slot], "GPS: %lf%s%s %lf%s%s %s", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, valid);
|
sprintf (state->dmr_embedded_gps[slot], "GPS: %lf%s%s %lf%s%s (%lf, %lf) %s", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude, longitude, valid);
|
||||||
|
|
||||||
|
//save to event history string
|
||||||
|
if (state->event_history_s[slot].Event_History_Items[0].source_id == src)
|
||||||
|
sprintf (state->event_history_s[slot].Event_History_Items[0].gps_s, "%s", state->dmr_embedded_gps[slot]);
|
||||||
|
|
||||||
//save to LRRP report for mapping/logging
|
//save to LRRP report for mapping/logging
|
||||||
FILE * pFile; //file pointer
|
FILE * pFile; //file pointer
|
||||||
if (opts->lrrp_file_output == 1)
|
if (opts->lrrp_file_output == 1)
|
||||||
{
|
{
|
||||||
int src = 0;
|
char * datestr = getDate();
|
||||||
if (slot == 0) src = state->lastsrc;
|
char * timestr = getTime();
|
||||||
if (slot == 1) src = state->lastsrcR;
|
|
||||||
|
|
||||||
//open file by name that is supplied in the ncurses terminal, or cli
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
pFile = fopen (opts->lrrp_out_file, "a");
|
pFile = fopen (opts->lrrp_out_file, "a");
|
||||||
fprintf (pFile, "%s\t", getDateL() );
|
fprintf (pFile, "%s\t", datestr );
|
||||||
fprintf (pFile, "%s\t", getTimeL() );
|
fprintf (pFile, "%s\t", timestr );
|
||||||
fprintf (pFile, "%08d\t", src);
|
fprintf (pFile, "%08d\t", src);
|
||||||
fprintf (pFile, "%.5lf\t", latitude);
|
fprintf (pFile, "%.5lf\t", latitude);
|
||||||
fprintf (pFile, "%.5lf\t", longitude);
|
fprintf (pFile, "%.5lf\t", longitude);
|
||||||
@@ -679,6 +777,17 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
fprintf (pFile, "\n");
|
fprintf (pFile, "\n");
|
||||||
fclose (pFile);
|
fclose (pFile);
|
||||||
|
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -686,3 +795,43 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
|||||||
|
|
||||||
fprintf (stderr, "%s", KNRM);
|
fprintf (stderr, "%s", KNRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decode_cellocator(dsd_opts * opts, dsd_state * state, uint8_t * input, int len)
|
||||||
|
{
|
||||||
|
//TODO: This
|
||||||
|
UNUSED(opts);
|
||||||
|
UNUSED(state);
|
||||||
|
UNUSED(input);
|
||||||
|
UNUSED(len);
|
||||||
|
|
||||||
|
//UTF8 Text: MCGP (0x4D434750) followed by data values
|
||||||
|
//(0417D1050000F45FD1DD00010000000097BDD56C81000009AAAABF12864C)
|
||||||
|
utf8_to_text(state, 0, 4, input);
|
||||||
|
|
||||||
|
fprintf (stderr, " Cellocator:");
|
||||||
|
|
||||||
|
uint8_t type = input[4];
|
||||||
|
if (type == 1) fprintf (stderr, " Platform Manifest Data;");
|
||||||
|
else if (type == 2) fprintf (stderr, " CAN Data;");
|
||||||
|
else if (type == 3) fprintf (stderr, " CAN Trigger Data;");
|
||||||
|
else if (type == 4) fprintf (stderr, " Time and Location Data;");
|
||||||
|
else if (type == 5) fprintf (stderr, " Accelerometer Data;");
|
||||||
|
else if (type == 6) fprintf (stderr, " PSP Alarm System Data;");
|
||||||
|
else if (type == 7) fprintf (stderr, " Usage Counter Data;");
|
||||||
|
else if (type == 8) fprintf (stderr, " Command Authentication Table Data;");
|
||||||
|
else if (type == 9) fprintf (stderr, " GSM Neighbor List Data;");
|
||||||
|
else if (type == 10) fprintf (stderr, " Maintenance Server Platform Manifest Data;");
|
||||||
|
else fprintf (stderr, " Unknown Data;");
|
||||||
|
|
||||||
|
//Data afterwards appears to be an arbitrary len so has variable reporting data
|
||||||
|
//will need to establish a len value for data and contents
|
||||||
|
|
||||||
|
}
|
||||||
|
void decode_ars(dsd_opts * opts, dsd_state * state, uint8_t * input, int len)
|
||||||
|
{
|
||||||
|
//TODO: This
|
||||||
|
UNUSED(opts);
|
||||||
|
UNUSED(state);
|
||||||
|
UNUSED(input);
|
||||||
|
UNUSED(len);
|
||||||
|
}
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ int csvKeyImportDec(dsd_opts * opts, dsd_state * state) //multi-key support
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Hex Variant of Key Import
|
//Hex Variant of Key Import
|
||||||
int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 keys
|
int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for hex keys
|
||||||
{
|
{
|
||||||
char filename[1024] = "filename.csv";
|
char filename[1024] = "filename.csv";
|
||||||
sprintf (filename, "%s", opts->key_in_file);
|
sprintf (filename, "%s", opts->key_in_file);
|
||||||
@@ -247,10 +247,31 @@ int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 key
|
|||||||
sscanf (field, "%llX", &state->rkey_array[keynumber]);
|
sscanf (field, "%llX", &state->rkey_array[keynumber]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//this could also theoretically nuke other keys that are at the same offset
|
||||||
|
if (field_count == 2)
|
||||||
|
{
|
||||||
|
sscanf (field, "%llX", &state->rkey_array[keynumber+0x101]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_count == 3)
|
||||||
|
{
|
||||||
|
sscanf (field, "%llX", &state->rkey_array[keynumber+0x201]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_count == 4)
|
||||||
|
{
|
||||||
|
sscanf (field, "%llX", &state->rkey_array[keynumber+0x301]);
|
||||||
|
}
|
||||||
|
|
||||||
field = strtok(NULL, ",");
|
field = strtok(NULL, ",");
|
||||||
field_count++;
|
field_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
|
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
|
||||||
|
|
||||||
|
//if longer key is loaded (or clash with the 0x101, 0x201, 0x301 offset, then print the full key listing)
|
||||||
|
if ( (state->rkey_array[keynumber+0x101] != 0) || (state->rkey_array[keynumber+0x201] != 0) || (state->rkey_array[keynumber+0x301] != 0) )
|
||||||
|
fprintf (stderr, " [%016llX] [%016llX] [%016llX]", state->rkey_array[keynumber+0x101], state->rkey_array[keynumber+0x201], state->rkey_array[keynumber+0x301]);
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
6258
src/dsd_main.c
6258
src/dsd_main.c
File diff suppressed because it is too large
Load Diff
1115
src/dsd_mbe.c
1115
src/dsd_mbe.c
File diff suppressed because it is too large
Load Diff
@@ -23,9 +23,10 @@
|
|||||||
void soft_demod_imbe7200 (dsd_state * state, char imbe_fr7200[8][23], char imbe_d[88])
|
void soft_demod_imbe7200 (dsd_state * state, char imbe_fr7200[8][23], char imbe_d[88])
|
||||||
{
|
{
|
||||||
state->errs = mbe_eccImbe7200x4400C0 (imbe_fr7200);
|
state->errs = mbe_eccImbe7200x4400C0 (imbe_fr7200);
|
||||||
|
state->errs2 = state->errs;
|
||||||
mbe_demodulateImbe7200x4400Data (imbe_fr7200);
|
mbe_demodulateImbe7200x4400Data (imbe_fr7200);
|
||||||
state->errs2 = mbe_eccImbe7200x4400Data (imbe_fr7200, imbe_d);
|
state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr7200, imbe_d);
|
||||||
state->debug_audio_errors += state->errs2 + state->errs;
|
state->debug_audio_errors += state->errs2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +34,10 @@ void soft_demod_imbe7200 (dsd_state * state, char imbe_fr7200[8][23], char imbe_
|
|||||||
void soft_demod_imbe7100 (dsd_state * state, char imbe_fr7100[7][24], char imbe_d[88])
|
void soft_demod_imbe7100 (dsd_state * state, char imbe_fr7100[7][24], char imbe_d[88])
|
||||||
{
|
{
|
||||||
state->errs = mbe_eccImbe7100x4400C0 (imbe_fr7100);
|
state->errs = mbe_eccImbe7100x4400C0 (imbe_fr7100);
|
||||||
|
state->errs2 = state->errs;
|
||||||
mbe_demodulateImbe7100x4400Data (imbe_fr7100);
|
mbe_demodulateImbe7100x4400Data (imbe_fr7100);
|
||||||
state->errs2 = mbe_eccImbe7100x4400Data (imbe_fr7100, imbe_d);
|
state->errs2 += mbe_eccImbe7100x4400Data (imbe_fr7100, imbe_d);
|
||||||
state->debug_audio_errors += state->errs2 + state->errs;
|
state->debug_audio_errors += state->errs2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,8 +45,9 @@ void soft_demod_imbe7100 (dsd_state * state, char imbe_fr7100[7][24], char imbe_
|
|||||||
void soft_demod_ambe2_ehr(dsd_state * state, char ambe2_ehr[4][24], char ambe_d[49])
|
void soft_demod_ambe2_ehr(dsd_state * state, char ambe2_ehr[4][24], char ambe_d[49])
|
||||||
{
|
{
|
||||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe2_ehr);
|
state->errs = mbe_eccAmbe3600x2450C0 (ambe2_ehr);
|
||||||
|
state->errs2 = state->errs;
|
||||||
mbe_demodulateAmbe3600x2450Data (ambe2_ehr);
|
mbe_demodulateAmbe3600x2450Data (ambe2_ehr);
|
||||||
state->errs2 = mbe_eccAmbe3600x2450Data (ambe2_ehr, ambe_d);
|
state->errs2 += mbe_eccAmbe3600x2450Data (ambe2_ehr, ambe_d);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +115,7 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb
|
|||||||
PrintAMBEData (opts, state, ambe_d);
|
PrintAMBEData (opts, state, ambe_d);
|
||||||
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||||
playSynthesizedVoice(opts, state);
|
playSynthesizedVoiceMS(opts, state);
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||||
playSynthesizedVoiceFM(opts, state);
|
playSynthesizedVoiceFM(opts, state);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||||
@@ -120,9 +123,11 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb
|
|||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
||||||
playSynthesizedVoiceFS(opts, state);
|
playSynthesizedVoiceFS(opts, state);
|
||||||
|
|
||||||
if (opts->wav_out_f != NULL)
|
if (opts->wav_out_f != NULL && opts->dmr_stereo_wav == 1)
|
||||||
writeSynthesizedVoice (opts, state);
|
writeSynthesizedVoice (opts, state);
|
||||||
|
|
||||||
|
//single wav file handled by playSynthesizedVoiceMS
|
||||||
|
|
||||||
if (opts->mbe_out_f != NULL)
|
if (opts->mbe_out_f != NULL)
|
||||||
saveAmbe2450Data (opts, state, ambe_d);
|
saveAmbe2450Data (opts, state, ambe_d);
|
||||||
}
|
}
|
||||||
@@ -135,7 +140,7 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb
|
|||||||
PrintAMBEData (opts, state, ambe_d);
|
PrintAMBEData (opts, state, ambe_d);
|
||||||
|
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||||
playSynthesizedVoice(opts, state);
|
playSynthesizedVoiceMS(opts, state);
|
||||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||||
playSynthesizedVoiceFM(opts, state);
|
playSynthesizedVoiceFM(opts, state);
|
||||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||||
|
|||||||
721
src/dsd_misc.c
Normal file
721
src/dsd_misc.c
Normal file
@@ -0,0 +1,721 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dsd_misc.c
|
||||||
|
* Misc Code that needs to be reorganized and sorted out
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
|
||||||
|
|
||||||
|
// trellis_1_2 encode: source is in bits, result in bits
|
||||||
|
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
||||||
|
{
|
||||||
|
for (int i=0; i<result_len; i+=2) {
|
||||||
|
reg = (reg << 1) | source[i>>1];
|
||||||
|
result[i] = PARITY[reg & 0x19];
|
||||||
|
result[i+1] = PARITY[reg & 0x17];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// simplified trellis 2:1 decode; source and result in bits
|
||||||
|
// assumes that encoding was done with NTEST trailing zero bits
|
||||||
|
// result_len should be set to the actual number of data bits
|
||||||
|
// in the original unencoded message (excl. these trailing bits)
|
||||||
|
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
||||||
|
{
|
||||||
|
int reg = 0;
|
||||||
|
int min_d;
|
||||||
|
int min_bt;
|
||||||
|
static const int NTEST = 4;
|
||||||
|
static const int NTESTC = 1 << NTEST;
|
||||||
|
uint8_t bt[NTEST];
|
||||||
|
uint8_t tt[NTEST*2];
|
||||||
|
int dstats[4];
|
||||||
|
int sum;
|
||||||
|
for (int p=0; p < 4; p++)
|
||||||
|
dstats[p] = 0;
|
||||||
|
for (int p=0; p < result_len; p++) {
|
||||||
|
for (int i=0; i<NTESTC; i++) {
|
||||||
|
bt[0] = (i&8)>>3;
|
||||||
|
bt[1] = (i&4)>>2;
|
||||||
|
bt[2] = (i&2)>>1;
|
||||||
|
bt[3] = (i&1);
|
||||||
|
trellis_encode(tt, bt, NTEST*2, reg);
|
||||||
|
sum=0;
|
||||||
|
for (int j=0; j<NTEST*2; j++) {
|
||||||
|
sum += tt[j] ^ source[p*2+j];
|
||||||
|
}
|
||||||
|
if (i == 0 || sum < min_d) {
|
||||||
|
min_d = sum;
|
||||||
|
min_bt = bt[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[p] = min_bt;
|
||||||
|
reg = (reg << 1) | min_bt;
|
||||||
|
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug output
|
||||||
|
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Original Copyright/License
|
||||||
|
|
||||||
|
/* -*- c++ -*- */
|
||||||
|
/*
|
||||||
|
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||||
|
*
|
||||||
|
* This file is part of OP25
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Ripped from libM17
|
||||||
|
#define K 5 //constraint length
|
||||||
|
#define NUM_STATES (1 << (K - 1)) //number of states
|
||||||
|
|
||||||
|
static uint32_t prevMetrics[NUM_STATES];
|
||||||
|
static uint32_t currMetrics[NUM_STATES];
|
||||||
|
static uint32_t prevMetricsData[NUM_STATES];
|
||||||
|
static uint32_t currMetricsData[NUM_STATES];
|
||||||
|
static uint16_t viterbi_history[244];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode unpunctured convolutionally encoded data.
|
||||||
|
*
|
||||||
|
* @param out Destination array where decoded data is written.
|
||||||
|
* @param in Input data.
|
||||||
|
* @param len Input length in bits.
|
||||||
|
* @return Number of bit errors corrected.
|
||||||
|
*/
|
||||||
|
uint32_t viterbi_decode(uint8_t* out, const uint16_t* in, const uint16_t len)
|
||||||
|
{
|
||||||
|
if(len > 244*2)
|
||||||
|
fprintf(stderr, "Input size exceeds max history\n");
|
||||||
|
|
||||||
|
viterbi_reset();
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
for(size_t i = 0; i < len; i += 2)
|
||||||
|
{
|
||||||
|
uint16_t s0 = in[i];
|
||||||
|
uint16_t s1 = in[i + 1];
|
||||||
|
|
||||||
|
viterbi_decode_bit(s0, s1, pos);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
uint32_t err = viterbi_chainback(out, pos, len/2);
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n vcb: \n");
|
||||||
|
// for (size_t i = 0; i < len; i++)
|
||||||
|
// fprintf (stderr, "%02X", out[i]);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode punctured convolutionally encoded data.
|
||||||
|
*
|
||||||
|
* @param out Destination array where decoded data is written.
|
||||||
|
* @param in Input data.
|
||||||
|
* @param punct Puncturing matrix.
|
||||||
|
* @param in_len Input data length.
|
||||||
|
* @param p_len Puncturing matrix length (entries).
|
||||||
|
* @return Number of bit errors corrected.
|
||||||
|
*/
|
||||||
|
uint32_t viterbi_decode_punctured(uint8_t* out, const uint16_t* in, const uint8_t* punct, const uint16_t in_len, const uint16_t p_len)
|
||||||
|
{
|
||||||
|
if(in_len > 244*2)
|
||||||
|
fprintf(stderr, "Input size exceeds max history\n");
|
||||||
|
|
||||||
|
uint16_t umsg[244*2]; //unpunctured message
|
||||||
|
uint8_t p=0; //puncturer matrix entry
|
||||||
|
uint16_t u=0; //bits count - unpunctured message
|
||||||
|
uint16_t i=0; //bits read from the input message
|
||||||
|
|
||||||
|
while(i<in_len)
|
||||||
|
{
|
||||||
|
if(punct[p])
|
||||||
|
{
|
||||||
|
umsg[u]=in[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
umsg[u]=0x7FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
u++;
|
||||||
|
p++;
|
||||||
|
p%=p_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, " p: %d, u: %d; p_len: %d; len: %d;", p, u, p_len, (u-in_len)*0x7FFF);
|
||||||
|
|
||||||
|
return viterbi_decode(out, umsg, u) - (u-in_len)*0x7FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decode one bit and update trellis.
|
||||||
|
*
|
||||||
|
* @param s0 Cost of the first symbol.
|
||||||
|
* @param s1 Cost of the second symbol.
|
||||||
|
* @param pos Bit position in history.
|
||||||
|
*/
|
||||||
|
void viterbi_decode_bit(uint16_t s0, uint16_t s1, const size_t pos)
|
||||||
|
{
|
||||||
|
static const uint16_t COST_TABLE_0[] = {0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||||
|
static const uint16_t COST_TABLE_1[] = {0, 0xFFFF, 0xFFFF, 0, 0, 0xFFFF, 0xFFFF, 0};
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < NUM_STATES/2; i++)
|
||||||
|
{
|
||||||
|
uint32_t metric = q_abs_diff(COST_TABLE_0[i], s0)
|
||||||
|
+ q_abs_diff(COST_TABLE_1[i], s1);
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t m0 = prevMetrics[i] + metric;
|
||||||
|
uint32_t m1 = prevMetrics[i + NUM_STATES/2] + (0x1FFFE - metric);
|
||||||
|
|
||||||
|
uint32_t m2 = prevMetrics[i] + (0x1FFFE - metric);
|
||||||
|
uint32_t m3 = prevMetrics[i + NUM_STATES/2] + metric;
|
||||||
|
|
||||||
|
uint8_t i0 = 2 * i;
|
||||||
|
uint8_t i1 = i0 + 1;
|
||||||
|
|
||||||
|
if(m0 >= m1)
|
||||||
|
{
|
||||||
|
viterbi_history[pos]|=(1<<i0);
|
||||||
|
currMetrics[i0] = m1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
viterbi_history[pos]&=~(1<<i0);
|
||||||
|
currMetrics[i0] = m0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m2 >= m3)
|
||||||
|
{
|
||||||
|
viterbi_history[pos]|=(1<<i1);
|
||||||
|
currMetrics[i1] = m3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
viterbi_history[pos]&=~(1<<i1);
|
||||||
|
currMetrics[i1] = m2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//swap
|
||||||
|
uint32_t tmp[NUM_STATES];
|
||||||
|
for(uint8_t i=0; i<NUM_STATES; i++)
|
||||||
|
{
|
||||||
|
tmp[i]=currMetrics[i];
|
||||||
|
}
|
||||||
|
for(uint8_t i=0; i<NUM_STATES; i++)
|
||||||
|
{
|
||||||
|
currMetrics[i]=prevMetrics[i];
|
||||||
|
prevMetrics[i]=tmp[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief History chainback to obtain final byte array.
|
||||||
|
*
|
||||||
|
* @param out Destination byte array for decoded data.
|
||||||
|
* @param pos Starting position for the chainback.
|
||||||
|
* @param len Length of the output in bits.
|
||||||
|
* @return Minimum Viterbi cost at the end of the decode sequence.
|
||||||
|
*/
|
||||||
|
uint32_t viterbi_chainback(uint8_t* out, size_t pos, uint16_t len)
|
||||||
|
{
|
||||||
|
uint8_t state = 0;
|
||||||
|
size_t bitPos = len+4;
|
||||||
|
|
||||||
|
memset(out, 0, (len-1)/8+1);
|
||||||
|
|
||||||
|
while(pos > 0)
|
||||||
|
{
|
||||||
|
bitPos--;
|
||||||
|
pos--;
|
||||||
|
uint16_t bit = viterbi_history[pos]&((1<<(state>>4)));
|
||||||
|
state >>= 1;
|
||||||
|
if(bit)
|
||||||
|
{
|
||||||
|
state |= 0x80;
|
||||||
|
out[bitPos/8]|=1<<(7-(bitPos%8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cost = prevMetrics[0];
|
||||||
|
|
||||||
|
for(size_t i = 0; i < NUM_STATES; i++)
|
||||||
|
{
|
||||||
|
uint32_t m = prevMetrics[i];
|
||||||
|
if(m < cost) cost = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug
|
||||||
|
// fprintf (stderr, "\n cb: \n");
|
||||||
|
// for (size_t i = 0; i < len; i++)
|
||||||
|
// fprintf (stderr, "%02X", out[i]);
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the decoder state. No args.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void viterbi_reset(void)
|
||||||
|
{
|
||||||
|
memset((uint8_t*)viterbi_history, 0, 2*244);
|
||||||
|
memset((uint8_t*)currMetrics, 0, 4*NUM_STATES);
|
||||||
|
memset((uint8_t*)prevMetrics, 0, 4*NUM_STATES);
|
||||||
|
memset((uint8_t*)currMetricsData, 0, 4*NUM_STATES);
|
||||||
|
memset((uint8_t*)prevMetricsData, 0, 4*NUM_STATES);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t q_abs_diff(const uint16_t v1, const uint16_t v2)
|
||||||
|
{
|
||||||
|
if(v2 > v1) return v2 - v1;
|
||||||
|
return v1 - v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//original sources
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// M17 C library - decode/viterbi.c
|
||||||
|
//
|
||||||
|
// This file contains:
|
||||||
|
// - the Viterbi decoder
|
||||||
|
//
|
||||||
|
// Wojciech Kaczmarski, SP5WWP
|
||||||
|
// M17 Project, 29 December 2023
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// M17 C library - math/math.c
|
||||||
|
//
|
||||||
|
// This file contains:
|
||||||
|
// - absolute difference value
|
||||||
|
// - Euclidean norm (L2) calculation for n-dimensional vectors (float)
|
||||||
|
// - soft-valued arrays to integer conversion (and vice-versa)
|
||||||
|
// - fixed-valued multiplication and division
|
||||||
|
//
|
||||||
|
// Wojciech Kaczmarski, SP5WWP
|
||||||
|
// M17 Project, 29 December 2023
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//audio filter stuff sourced from: https://github.com/NedSimao/FilteringLibrary
|
||||||
|
//no license / information provided in source code
|
||||||
|
#define PI 3.141592653
|
||||||
|
|
||||||
|
//do we need this for test input sthit?
|
||||||
|
// #define PLOT_POINTS 100
|
||||||
|
// #define SAMPLE_TIME_S 0.001
|
||||||
|
// #define CUTOFFFREQ_HZ 50
|
||||||
|
// #define sine_freq 40
|
||||||
|
// #define sine_freq_1 500
|
||||||
|
// #define HFC 50
|
||||||
|
// #define LFC 100
|
||||||
|
|
||||||
|
|
||||||
|
void LPFilter_Init(LPFilter *filter, float cutoffFreqHz, float sampleTimeS)
|
||||||
|
{
|
||||||
|
|
||||||
|
float RC=0.0;
|
||||||
|
RC=1.0/(2*PI*cutoffFreqHz);
|
||||||
|
filter->coef[0]=sampleTimeS/(sampleTimeS+RC);
|
||||||
|
filter->coef[1]=RC/(sampleTimeS+RC);
|
||||||
|
|
||||||
|
filter->v_out[0]=0.0;
|
||||||
|
filter->v_out[1]=0.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float LPFilter_Update(LPFilter *filter, float v_in)
|
||||||
|
{
|
||||||
|
|
||||||
|
filter->v_out[1]=filter->v_out[0];
|
||||||
|
filter->v_out[0]=(filter->coef[0]*v_in) + (filter->coef[1]*filter->v_out[1]);
|
||||||
|
|
||||||
|
return (filter->v_out[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* HIGH PASS FILTER
|
||||||
|
********************************************************************************************************/
|
||||||
|
void HPFilter_Init(HPFilter *filter, float cutoffFreqHz, float sampleTimeS)
|
||||||
|
{
|
||||||
|
|
||||||
|
float RC=0.0;
|
||||||
|
RC=1.0/(2*PI*cutoffFreqHz);
|
||||||
|
|
||||||
|
filter->coef=RC/(sampleTimeS+RC);
|
||||||
|
|
||||||
|
filter->v_in[0]=0.0;
|
||||||
|
filter->v_in[1]=0.0;
|
||||||
|
|
||||||
|
filter->v_out[0]=0.0;
|
||||||
|
filter->v_out[1]=0.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float HPFilter_Update(HPFilter *filter, float v_in)
|
||||||
|
{
|
||||||
|
|
||||||
|
filter->v_in[1]=filter->v_in[0];
|
||||||
|
filter->v_in[0]=v_in;
|
||||||
|
|
||||||
|
filter->v_out[1]=filter->v_out[0];
|
||||||
|
filter->v_out[0]=filter->coef * (filter->v_in[0] - filter->v_in[1]+filter->v_out[1]);
|
||||||
|
|
||||||
|
return (filter->v_out[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* BAND PASS FILTER
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS)
|
||||||
|
{
|
||||||
|
|
||||||
|
LPFilter_Init(&filter->lpf, LPF_cutoffFreqHz, sampleTimeS);
|
||||||
|
HPFilter_Init(&filter->hpf, HPF_cutoffFreqHz, sampleTimeS);
|
||||||
|
|
||||||
|
filter->out_in=0.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float PBFilter_Update(PBFilter *filter, float v_in)
|
||||||
|
{
|
||||||
|
|
||||||
|
filter->out_in=HPFilter_Update(&filter->hpf, v_in);
|
||||||
|
|
||||||
|
filter->out_in=LPFilter_Update(&filter->lpf, filter->out_in);
|
||||||
|
|
||||||
|
return (filter->out_in);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************************************************
|
||||||
|
* NOTCH FILTER
|
||||||
|
********************************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
void NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS)
|
||||||
|
{
|
||||||
|
|
||||||
|
//filter frequency to angular (rad/s)
|
||||||
|
float w0_rps=2.0 * PI *centerFreqHz;
|
||||||
|
float ww_rps=2.0 * PI *notchWidthHz;
|
||||||
|
|
||||||
|
//pre warp center frequency
|
||||||
|
float w0_pw_rps=(2.0/sampleTimeS) * tanf(0.5 * w0_rps * sampleTimeS);
|
||||||
|
|
||||||
|
//computing filter coefficients
|
||||||
|
|
||||||
|
filter->alpha=4.0 + w0_rps*w0_pw_rps*sampleTimeS*sampleTimeS;
|
||||||
|
filter->beta=2.0*ww_rps*sampleTimeS;
|
||||||
|
|
||||||
|
//clearing input and output buffers
|
||||||
|
|
||||||
|
for (uint8_t n=0; n<3; n++)
|
||||||
|
{
|
||||||
|
filter->vin[n]=0;
|
||||||
|
filter->vout[n]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
float NOTCHFilter_Update(NOTCHFilter *filter, float vin)
|
||||||
|
{
|
||||||
|
|
||||||
|
//shifting samples
|
||||||
|
filter->vin[2]=filter->vin[1];
|
||||||
|
filter->vin[1]=filter->vin[0];
|
||||||
|
|
||||||
|
filter->vout[2]=filter->vout[1];
|
||||||
|
filter->vout[1]=filter->vout[0];
|
||||||
|
|
||||||
|
filter->vin[0]=vin;
|
||||||
|
|
||||||
|
//compute new output
|
||||||
|
filter->vout[0]=(filter->alpha*filter->vin[0] + 2.0 *(filter->alpha -8.0)*filter->vin[1] + filter->alpha*filter->vin[2]
|
||||||
|
-(2.0f*(filter->alpha-8.0)*filter->vout[1]+(filter->alpha-filter->beta)*filter->vout[2]))/(filter->alpha+filter->beta);
|
||||||
|
|
||||||
|
|
||||||
|
return (filter->vout[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_audio_filters (dsd_state * state)
|
||||||
|
{
|
||||||
|
//still not sure if this is even correct or not, but 48k sounds good now
|
||||||
|
LPFilter_Init(&state->RCFilter, 960, (float)1/(float)48000);
|
||||||
|
HPFilter_Init(&state->HRCFilter, 960, (float)1/(float)48000);
|
||||||
|
|
||||||
|
//left and right variants for stereo output testing on digital voice samples
|
||||||
|
LPFilter_Init(&state->RCFilterL, 960, (float)1/(float)16000);
|
||||||
|
HPFilter_Init(&state->HRCFilterL, 960, (float)1/(float)16000);
|
||||||
|
LPFilter_Init(&state->RCFilterR, 960, (float)1/(float)16000);
|
||||||
|
HPFilter_Init(&state->HRCFilterR, 960, (float)1/(float)16000);
|
||||||
|
|
||||||
|
//PBFilter_Init(PBFilter *filter, float HPF_cutoffFreqHz, float LPF_cutoffFreqHz, float sampleTimeS);
|
||||||
|
//NOTCHFilter_Init(NOTCHFilter *filter, float centerFreqHz, float notchWidthHz, float sampleTimeS);
|
||||||
|
|
||||||
|
//NOTE: PBFilter_init also inits a LPF and HPF, but on another set of filters, might be worth
|
||||||
|
//testing just using the PBFilter by itself and see how it does without the hpf used
|
||||||
|
|
||||||
|
//passband filter working (seems to be), notch filter unsure which values to use, doesn't have any appreciable affect when used as is
|
||||||
|
PBFilter_Init(&state->PBF, 8000, 12000, (float)1/(float)1536000); //RTL Sampling at 1536000 S/s.
|
||||||
|
NOTCHFilter_Init(&state->NF, 1000, 4000, (float)1/(float)1536000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//FUNCTIONS for handing use of above filters
|
||||||
|
|
||||||
|
//lpf
|
||||||
|
void lpf(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = LPFilter_Update(&state->RCFilter, input[i]);
|
||||||
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//hpf
|
||||||
|
void hpf(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = HPFilter_Update(&state->HRCFilter, input[i]);
|
||||||
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//hpf digital left
|
||||||
|
void hpf_dL(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = HPFilter_Update(&state->HRCFilterL, input[i]);
|
||||||
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//hpf digital right
|
||||||
|
void hpf_dR(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = HPFilter_Update(&state->HRCFilterR, input[i]);
|
||||||
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nf
|
||||||
|
void nf(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = NOTCHFilter_Update(&state->NF, input[i]);
|
||||||
|
// fprintf (stderr, "\n out: %05d", input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//pbf
|
||||||
|
void pbf(dsd_state * state, short * input, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
// fprintf (stderr, "\n in: %05d", input[i]);
|
||||||
|
input[i] = PBFilter_Update(&state->PBF, input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generic RMS function derived from RTL_FM (RTL_SDR) RMS code (doesnt' really work correctly outside of RTL)
|
||||||
|
long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
long int rms;
|
||||||
|
long p, t, s;
|
||||||
|
double dc, err;
|
||||||
|
|
||||||
|
p = t = 0L;
|
||||||
|
for (i=0; i<len; i+=step) {
|
||||||
|
s = (long)samples[i];
|
||||||
|
t += s;
|
||||||
|
p += s * s;
|
||||||
|
}
|
||||||
|
/* correct for dc offset in squares */
|
||||||
|
dc = (double)(t*step) / (double)len;
|
||||||
|
err = t * 2 * dc - dc * dc * len;
|
||||||
|
|
||||||
|
rms = (long int)sqrt((p-err) / len);
|
||||||
|
if (rms < 0) rms = 150;
|
||||||
|
return rms;
|
||||||
|
}
|
||||||
|
|
||||||
|
//same as symbol levels in m17.h (m17-fme version)
|
||||||
|
const int8_t symbol_list[4]={-3, -1, +1, +3};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Slice payload symbols into soft dibits.
|
||||||
|
* Input (RRC filtered baseband sampled at symbol centers)
|
||||||
|
* should be already normalized to {-3, -1, +1 +3}.
|
||||||
|
* @param out Soft valued dibits (type-4).
|
||||||
|
* @param inp Array of 184 floats (1 sample per symbol).
|
||||||
|
*/
|
||||||
|
void slice_symbols(uint16_t out[2*SYM_PER_PLD], const float inp[SYM_PER_PLD])
|
||||||
|
{
|
||||||
|
|
||||||
|
for(uint8_t i=0; i<SYM_PER_PLD; i++)
|
||||||
|
{
|
||||||
|
//bit 0
|
||||||
|
if(inp[i]>=symbol_list[3])
|
||||||
|
{
|
||||||
|
out[i*2+1]=0xFFFF;
|
||||||
|
}
|
||||||
|
else if(inp[i]>=symbol_list[2])
|
||||||
|
{
|
||||||
|
out[i*2+1]=-(float)0xFFFF/(symbol_list[3]-symbol_list[2])*symbol_list[2]+inp[i]*(float)0xFFFF/(symbol_list[3]-symbol_list[2]);
|
||||||
|
}
|
||||||
|
else if(inp[i]>=symbol_list[1])
|
||||||
|
{
|
||||||
|
out[i*2+1]=0x0000;
|
||||||
|
}
|
||||||
|
else if(inp[i]>=symbol_list[0])
|
||||||
|
{
|
||||||
|
out[i*2+1]=(float)0xFFFF/(symbol_list[1]-symbol_list[0])*symbol_list[1]-inp[i]*(float)0xFFFF/(symbol_list[1]-symbol_list[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out[i*2+1]=0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bit 1
|
||||||
|
if(inp[i]>=symbol_list[2])
|
||||||
|
{
|
||||||
|
out[i*2]=0x0000;
|
||||||
|
}
|
||||||
|
else if(inp[i]>=symbol_list[1])
|
||||||
|
{
|
||||||
|
out[i*2]=0x7FFF-inp[i]*(float)0xFFFF/(symbol_list[2]-symbol_list[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out[i*2]=0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Soft logic NOT.
|
||||||
|
*
|
||||||
|
* @param a Input A.
|
||||||
|
* @return uint16_t Output = not A.
|
||||||
|
*/
|
||||||
|
uint16_t soft_bit_NOT(const uint16_t a)
|
||||||
|
{
|
||||||
|
return 0xFFFFU-a;
|
||||||
|
}
|
||||||
|
|
||||||
|
//randomizing pattern
|
||||||
|
const uint8_t rand_seq[46]=
|
||||||
|
{
|
||||||
|
0xD6, 0xB5, 0xE2, 0x30, 0x82, 0xFF, 0x84, 0x62, 0xBA, 0x4E, 0x96, 0x90, 0xD8, 0x98, 0xDD, 0x5D, 0x0C, 0xC8, 0x52, 0x43, 0x91, 0x1D, 0xF8,
|
||||||
|
0x6E, 0x68, 0x2F, 0x35, 0xDA, 0x14, 0xEA, 0xCD, 0x76, 0x19, 0x8D, 0xD5, 0x80, 0xD1, 0x33, 0x87, 0x13, 0x57, 0x18, 0x2D, 0x29, 0x78, 0xC3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Randomize type-4 soft bits.
|
||||||
|
*
|
||||||
|
* @param inp Input 368 soft type-4 bits.
|
||||||
|
*/
|
||||||
|
void randomize_soft_bits(uint16_t inp[SYM_PER_PLD*2])
|
||||||
|
{
|
||||||
|
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||||
|
{
|
||||||
|
if((rand_seq[i/8]>>(7-(i%8)))&1) //flip bit if '1'
|
||||||
|
{
|
||||||
|
inp[i]=soft_bit_NOT(inp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//interleaver pattern
|
||||||
|
const uint16_t intrl_seq[SYM_PER_PLD*2]=
|
||||||
|
{
|
||||||
|
0, 137, 90, 227, 180, 317, 270, 39, 360, 129, 82, 219, 172, 309, 262, 31,
|
||||||
|
352, 121, 74, 211, 164, 301, 254, 23, 344, 113, 66, 203, 156, 293, 246, 15,
|
||||||
|
336, 105, 58, 195, 148, 285, 238, 7, 328, 97, 50, 187, 140, 277, 230, 367,
|
||||||
|
320, 89, 42, 179, 132, 269, 222, 359, 312, 81, 34, 171, 124, 261, 214, 351,
|
||||||
|
304, 73, 26, 163, 116, 253, 206, 343, 296, 65, 18, 155, 108, 245, 198, 335,
|
||||||
|
288, 57, 10, 147, 100, 237, 190, 327, 280, 49, 2, 139, 92, 229, 182, 319,
|
||||||
|
272, 41, 362, 131, 84, 221, 174, 311, 264, 33, 354, 123, 76, 213, 166, 303,
|
||||||
|
256, 25, 346, 115, 68, 205, 158, 295, 248, 17, 338, 107, 60, 197, 150, 287,
|
||||||
|
240, 9, 330, 99, 52, 189, 142, 279, 232, 1, 322, 91, 44, 181, 134, 271,
|
||||||
|
224, 361, 314, 83, 36, 173, 126, 263, 216, 353, 306, 75, 28, 165, 118, 255,
|
||||||
|
208, 345, 298, 67, 20, 157, 110, 247, 200, 337, 290, 59, 12, 149, 102, 239,
|
||||||
|
192, 329, 282, 51, 4, 141, 94, 231, 184, 321, 274, 43, 364, 133, 86, 223,
|
||||||
|
176, 313, 266, 35, 356, 125, 78, 215, 168, 305, 258, 27, 348, 117, 70, 207,
|
||||||
|
160, 297, 250, 19, 340, 109, 62, 199, 152, 289, 242, 11, 332, 101, 54, 191,
|
||||||
|
144, 281, 234, 3, 324, 93, 46, 183, 136, 273, 226, 363, 316, 85, 38, 175,
|
||||||
|
128, 265, 218, 355, 308, 77, 30, 167, 120, 257, 210, 347, 300, 69, 22, 159,
|
||||||
|
112, 249, 202, 339, 292, 61, 14, 151, 104, 241, 194, 331, 284, 53, 6, 143,
|
||||||
|
96, 233, 186, 323, 276, 45, 366, 135, 88, 225, 178, 315, 268, 37, 358, 127,
|
||||||
|
80, 217, 170, 307, 260, 29, 350, 119, 72, 209, 162, 299, 252, 21, 342, 111,
|
||||||
|
64, 201, 154, 291, 244, 13, 334, 103, 56, 193, 146, 283, 236, 5, 326, 95,
|
||||||
|
48, 185, 138, 275, 228, 365, 318, 87, 40, 177, 130, 267, 220, 357, 310, 79,
|
||||||
|
32, 169, 122, 259, 212, 349, 302, 71, 24, 161, 114, 251, 204, 341, 294, 63,
|
||||||
|
16, 153, 106, 243, 196, 333, 286, 55, 8, 145, 98, 235, 188, 325, 278, 47
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reorder (interleave) 368 soft bits.
|
||||||
|
*
|
||||||
|
* @param outp Reordered soft bits.
|
||||||
|
* @param inp Input soft bits.
|
||||||
|
*/
|
||||||
|
void reorder_soft_bits(uint16_t outp[SYM_PER_PLD*2], const uint16_t inp[SYM_PER_PLD*2])
|
||||||
|
{
|
||||||
|
for(uint16_t i=0; i<SYM_PER_PLD*2; i++)
|
||||||
|
outp[i]=inp[intrl_seq[i]];
|
||||||
|
}
|
||||||
4208
src/dsd_ncurses.c
4208
src/dsd_ncurses.c
File diff suppressed because it is too large
Load Diff
925
src/dsd_ncurses_handler.c
Normal file
925
src/dsd_ncurses_handler.c
Normal file
@@ -0,0 +1,925 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dsd_ncurses_handler.c
|
||||||
|
* DSD-FME ncurses terminal user input handler
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2025-05 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
uint8_t ncurses_input_handler(dsd_opts * opts, dsd_state * state, int c)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct stat st_wav = {0};
|
||||||
|
|
||||||
|
// //debug char value
|
||||||
|
// if (c != -1)
|
||||||
|
// fprintf (stderr, "\n User Input: %i / %c ;;", c, c);
|
||||||
|
|
||||||
|
//TEST: Handle Escape Characters
|
||||||
|
//if issues arise, just go back to the way it was before
|
||||||
|
//this is primarly a fix for scroll wheel activatign the menu
|
||||||
|
//and Windows Powershell right-click doing a copy and paste
|
||||||
|
//and sendign tons of garbage getch chars here and changing things
|
||||||
|
if (c == '\033')
|
||||||
|
{
|
||||||
|
//TODO: Find way to getch all the chars immediately after, or just
|
||||||
|
//run getch in a loop in case of somebody copying and pasting a ton of things accidentally
|
||||||
|
for (int i = 0; i < 100000; i++) //wonder how slow this will be
|
||||||
|
getch();
|
||||||
|
c = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//keyboard shortcuts - codes same as ascii codes
|
||||||
|
if (c == 10) //Return / Enter key, open menu
|
||||||
|
ncursesMenu (opts, state);
|
||||||
|
|
||||||
|
//use k and l keys to test tg hold toggles on slots 1 and slots 2
|
||||||
|
if (c == 107) //'k' key, hold tg on slot 1 for trunking purposes, or toggle clear
|
||||||
|
{
|
||||||
|
if (state->tg_hold == 0)
|
||||||
|
state->tg_hold = state->lasttg;
|
||||||
|
else state->tg_hold = 0;
|
||||||
|
|
||||||
|
if ( (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1) && (state->tg_hold == 0) )
|
||||||
|
state->tg_hold = state->nxdn_last_tg;
|
||||||
|
|
||||||
|
else if (opts->frame_provoice == 1 && state->ea_mode == 0)
|
||||||
|
state->tg_hold = state->lastsrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 108) //'l' key, hold tg on slot 2 for trunking purposes, or toggle clear
|
||||||
|
{
|
||||||
|
if (state->tg_hold == 0)
|
||||||
|
state->tg_hold = state->lasttgR;
|
||||||
|
else state->tg_hold = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//toggling when 48k/1 OSS still has some lag -- needed to clear out the buffer when switching
|
||||||
|
if (c == 49) // '1' key, toggle slot1 on
|
||||||
|
{
|
||||||
|
//switching, but want to control each seperately plz
|
||||||
|
if (opts->slot1_on == 1)
|
||||||
|
{
|
||||||
|
opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
||||||
|
// opts->slot_preference = 1; //slot 2
|
||||||
|
//clear any previously buffered audio
|
||||||
|
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||||
|
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||||
|
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||||
|
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||||
|
state->audio_out_idx2 = 0;
|
||||||
|
state->audio_out_idx = 0;
|
||||||
|
}
|
||||||
|
else if (opts->slot1_on == 0)
|
||||||
|
{
|
||||||
|
opts->slot1_on = 1;
|
||||||
|
if (opts->audio_out_type == 5) //OSS 48k/1
|
||||||
|
{
|
||||||
|
opts->slot_preference = 0; //slot 1
|
||||||
|
// opts->slot2_on = 0; //turn off slot 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 50) // '2' key, toggle slot2 on
|
||||||
|
{
|
||||||
|
//switching, but want to control each seperately plz
|
||||||
|
if (opts->slot2_on == 1)
|
||||||
|
{
|
||||||
|
opts->slot2_on = 0;
|
||||||
|
opts->slot_preference = 0; //slot 1
|
||||||
|
//clear any previously buffered audio
|
||||||
|
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||||
|
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||||
|
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||||
|
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||||
|
state->audio_out_idx2R = 0;
|
||||||
|
state->audio_out_idxR = 0;
|
||||||
|
}
|
||||||
|
else if (opts->slot2_on == 0)
|
||||||
|
{
|
||||||
|
opts->slot2_on = 1;
|
||||||
|
if (opts->audio_out_type == 5) //OSS 48k/1
|
||||||
|
{
|
||||||
|
opts->slot_preference = 1; //slot 2
|
||||||
|
// opts->slot1_on = 0; //turn off slot 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (c == 51) //'3' key, toggle slot preference on 48k/1
|
||||||
|
// {
|
||||||
|
// if (opts->slot_preference == 1) opts->slot_preference = 0;
|
||||||
|
// else opts->slot_preference = 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (c == 51) //'3' key, cycle slot preference
|
||||||
|
{
|
||||||
|
if (opts->slot_preference == 0 || opts->slot_preference == 1) opts->slot_preference++;
|
||||||
|
else opts->slot_preference = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 43) //+ key, increment audio_gain
|
||||||
|
{
|
||||||
|
|
||||||
|
if (opts->audio_gain < 50)
|
||||||
|
opts->audio_gain++;
|
||||||
|
|
||||||
|
state->aout_gain = opts->audio_gain;
|
||||||
|
state->aout_gainR = opts->audio_gain;
|
||||||
|
|
||||||
|
opts->audio_gainR = opts->audio_gain;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 45) //- key, decrement audio_gain
|
||||||
|
{
|
||||||
|
|
||||||
|
if (opts->audio_gain > 0)
|
||||||
|
opts->audio_gain--;
|
||||||
|
|
||||||
|
state->aout_gain = opts->audio_gain;
|
||||||
|
state->aout_gainR = opts->audio_gain;
|
||||||
|
|
||||||
|
//reset to default on 0 for auto
|
||||||
|
if (opts->audio_gain == 0)
|
||||||
|
{
|
||||||
|
state->aout_gain = 25;
|
||||||
|
state->aout_gainR = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts->audio_gainR = opts->audio_gain;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 42) // * key, increment audio_gainA
|
||||||
|
{
|
||||||
|
if (opts->audio_gainA < 100)
|
||||||
|
opts->audio_gainA++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 47) // / key, decrement audio_gainA
|
||||||
|
{
|
||||||
|
if (opts->audio_gainA > 0)
|
||||||
|
opts->audio_gainA--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 122) //'z' key, toggle payload to console
|
||||||
|
{
|
||||||
|
if (opts->payload == 1) opts->payload = 0;
|
||||||
|
else opts->payload = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 99) //'c' key, toggle compact mode
|
||||||
|
{
|
||||||
|
if (opts->ncurses_compact == 1) opts->ncurses_compact = 0;
|
||||||
|
else opts->ncurses_compact = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 116) //'t' key, toggle trunking
|
||||||
|
{
|
||||||
|
if (opts->p25_trunk == 1) opts->p25_trunk = 0;
|
||||||
|
else opts->p25_trunk = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 121) //'y' key, toggle scanner mode
|
||||||
|
{
|
||||||
|
if (opts->scanner_mode == 1) opts->scanner_mode = 0;
|
||||||
|
else opts->scanner_mode = 1;
|
||||||
|
opts->p25_trunk = 0; //turn off trunking mode
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 97) //'a' key, toggle call alert beep
|
||||||
|
{
|
||||||
|
if (opts->call_alert == 1) opts->call_alert = 0;
|
||||||
|
else opts->call_alert = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 104) //'h' key, cycle history off, short, long
|
||||||
|
{
|
||||||
|
opts->ncurses_history++;
|
||||||
|
opts->ncurses_history %= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 113) //'q' key, quit
|
||||||
|
{
|
||||||
|
exitflag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 52) // '4' key, toggle force privacy key over fid and svc (dmr)
|
||||||
|
{
|
||||||
|
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||||
|
else state->forced_alg_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 54) // '6' key, toggle force rc4 key over missing pi header/late entry
|
||||||
|
{
|
||||||
|
if (state->forced_alg_id == 1 || state->forced_alg_id == 0x21) state->forced_alg_id = 0;
|
||||||
|
else state->forced_alg_id = 0x21;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 105) //'i' key, toggle signal inversion on inverted types
|
||||||
|
{
|
||||||
|
//Set all signal for inversion or uninversion
|
||||||
|
if (opts->inverted_dmr == 0)
|
||||||
|
{
|
||||||
|
opts->inverted_dmr = 1;
|
||||||
|
opts->inverted_dpmr = 1;
|
||||||
|
opts->inverted_x2tdma = 1;
|
||||||
|
opts->inverted_ysf = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opts->inverted_dmr = 0;
|
||||||
|
opts->inverted_dpmr = 0;
|
||||||
|
opts->inverted_x2tdma = 0;
|
||||||
|
opts->inverted_ysf = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 109) //'m' key, toggle qpsk/c4fm - everything but phase 2
|
||||||
|
{
|
||||||
|
if (state->rf_mod == 0)
|
||||||
|
{
|
||||||
|
opts->mod_c4fm = 0;
|
||||||
|
opts->mod_qpsk = 1;
|
||||||
|
opts->mod_gfsk = 0;
|
||||||
|
state->rf_mod = 1;
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opts->mod_c4fm = 1;
|
||||||
|
opts->mod_qpsk = 0;
|
||||||
|
opts->mod_gfsk = 0;
|
||||||
|
state->rf_mod = 0;
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 77) //'M' key, toggle qpsk - phase 2 6000 sps
|
||||||
|
{
|
||||||
|
if (state->rf_mod == 0)
|
||||||
|
{
|
||||||
|
opts->mod_c4fm = 0;
|
||||||
|
opts->mod_qpsk = 1;
|
||||||
|
opts->mod_gfsk = 0;
|
||||||
|
state->rf_mod = 1;
|
||||||
|
state->samplesPerSymbol = 8;
|
||||||
|
state->symbolCenter = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opts->mod_c4fm = 1;
|
||||||
|
opts->mod_qpsk = 0;
|
||||||
|
opts->mod_gfsk = 0;
|
||||||
|
state->rf_mod = 0;
|
||||||
|
state->samplesPerSymbol = 8;
|
||||||
|
state->symbolCenter = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 82) //'R', save symbol capture bin with date/time string as name
|
||||||
|
{
|
||||||
|
//for filenames (no colons, etc)
|
||||||
|
char * timestr = getTime();
|
||||||
|
char * datestr = getDate();
|
||||||
|
sprintf (opts->symbol_out_file, "%s_%s_dibit_capture.bin", datestr, timestr);
|
||||||
|
openSymbolOutFile (opts, state);
|
||||||
|
|
||||||
|
//add a system event to echo in the event history
|
||||||
|
state->event_history_s[0].Event_History_Items[0].color_pair = 4;
|
||||||
|
char event_str[2000]; memset (event_str, 0, sizeof(event_str));
|
||||||
|
sprintf (event_str, "DSD-FME Dibit Capture File Started: %s;", opts->symbol_out_file);
|
||||||
|
watchdog_event_datacall (opts, state, 0xFFFFFF, 0xFFFFFF, event_str, 0);
|
||||||
|
state->lastsrc = 0; //this could wipe a call src if they hit 'R' while call in slot 1 in progress
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
|
//allocated memory pointer needs to be free'd
|
||||||
|
if (timestr != NULL)
|
||||||
|
{
|
||||||
|
free (timestr);
|
||||||
|
timestr = NULL;
|
||||||
|
}
|
||||||
|
if (datestr != NULL)
|
||||||
|
{
|
||||||
|
free (datestr);
|
||||||
|
datestr = NULL;
|
||||||
|
}
|
||||||
|
opts->symbol_out_file_creation_time = time(NULL);
|
||||||
|
opts->symbol_out_file_is_auto = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 114) //'r' key, stop capturing symbol capture bin file
|
||||||
|
{
|
||||||
|
if (opts->symbol_out_f)
|
||||||
|
{
|
||||||
|
closeSymbolOutFile (opts, state);
|
||||||
|
sprintf (opts->audio_in_dev, "%s", opts->symbol_out_file);
|
||||||
|
|
||||||
|
//add a system event to echo in the event history
|
||||||
|
state->event_history_s[0].Event_History_Items[0].color_pair = 4;
|
||||||
|
char event_str[2000]; memset (event_str, 0, sizeof(event_str));
|
||||||
|
sprintf (event_str, "DSD-FME Dibit Capture File Closed: %s;", opts->symbol_out_file);
|
||||||
|
watchdog_event_datacall (opts, state, 0xFFFFFF, 0xFFFFFF, event_str, 0);
|
||||||
|
state->lastsrc = 0; //this could wipe a call src if they hit 'R' while call in slot 1 in progress
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
opts->symbol_out_file_is_auto = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __CYGWIN__
|
||||||
|
//do nothing
|
||||||
|
#else
|
||||||
|
if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
|
||||||
|
{
|
||||||
|
struct stat stat_buf;
|
||||||
|
if (stat(opts->audio_in_dev, &stat_buf) != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev);
|
||||||
|
goto SKIPR;
|
||||||
|
}
|
||||||
|
if (S_ISREG(stat_buf.st_mode))
|
||||||
|
{
|
||||||
|
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||||
|
opts->audio_in_type = 4; //symbol capture bin files
|
||||||
|
}
|
||||||
|
SKIPR: ; //do nothing
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (c == 80) //'P' key - start per call wav files //TODO: Fix
|
||||||
|
{
|
||||||
|
char wav_file_directory[1024];
|
||||||
|
sprintf (wav_file_directory, "%s", opts->wav_out_dir);
|
||||||
|
wav_file_directory[1023] = '\0';
|
||||||
|
if (stat(wav_file_directory, &st_wav) == -1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s wav file directory does not exist\n", wav_file_directory);
|
||||||
|
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
|
||||||
|
mkdir(wav_file_directory, 0700);
|
||||||
|
}
|
||||||
|
fprintf (stderr,"\n Per Call Wav File Enabled to Directory: %s;.\n", opts->wav_out_dir);
|
||||||
|
srand(time(NULL)); //seed random for filenames (so two filenames aren't the exact same datetime string on initailization)
|
||||||
|
opts->wav_out_f = open_wav_file(opts->wav_out_dir, opts->wav_out_file, 8000, 0);
|
||||||
|
opts->wav_out_fR = open_wav_file(opts->wav_out_dir, opts->wav_out_fileR, 8000, 0);
|
||||||
|
opts->dmr_stereo_wav = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 112) //'p' key - stop all per call wav files //TODO: Fix
|
||||||
|
{
|
||||||
|
//TODO: Add Closing of RAW files as well?
|
||||||
|
opts->wav_out_f = close_and_rename_wav_file(opts->wav_out_f, opts->wav_out_file, opts->wav_out_dir, &state->event_history_s[0]);
|
||||||
|
opts->wav_out_fR = close_and_rename_wav_file(opts->wav_out_fR, opts->wav_out_fileR, opts->wav_out_dir, &state->event_history_s[1]);
|
||||||
|
opts->wav_out_file[0] = 0; //Bugfix for decoded wav file display after disabling
|
||||||
|
opts->wav_out_fileR[0] = 0;
|
||||||
|
opts->dmr_stereo_wav = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
#ifdef __CYGWIN__ //this might be okay on Aero as well, will need to look into and/or test
|
||||||
|
//
|
||||||
|
#else
|
||||||
|
if (c == 115) //'s' key, stop playing wav or symbol in files
|
||||||
|
{
|
||||||
|
if (opts->symbolfile != NULL)
|
||||||
|
{
|
||||||
|
if (opts->audio_in_type == 4)
|
||||||
|
{
|
||||||
|
fclose(opts->symbolfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->audio_in_type == 2) //wav input file
|
||||||
|
{
|
||||||
|
sf_close(opts->audio_in_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->audio_out_type == 0)
|
||||||
|
{
|
||||||
|
opts->audio_in_type = 0;
|
||||||
|
openPulseInput(opts);
|
||||||
|
}
|
||||||
|
else opts->audio_in_type = 5; //exitflag = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//makes buzzing sound when locked out in new audio config and short, probably something to do with processaudio running or not running
|
||||||
|
if (state->lasttg != 0 && opts->frame_provoice != 1 && c == 33) //SHIFT+'1' key (exclamation point), lockout slot 1 or conventional tg from tuning/playback during session
|
||||||
|
{
|
||||||
|
state->group_array[state->group_tally].groupNumber = state->lasttg;
|
||||||
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||||||
|
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||||||
|
state->group_tally++;
|
||||||
|
|
||||||
|
sprintf (state->event_history_s[0].Event_History_Items[0].internal_str, "Target: %d; has been locked out; User Lock Out.", state->lasttg);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||||
|
|
||||||
|
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||||||
|
if (opts->group_in_file[0] != 0) //file is available
|
||||||
|
{
|
||||||
|
FILE * pFile; //file pointer
|
||||||
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
|
pFile = fopen (opts->group_in_file, "a");
|
||||||
|
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttg, state->payload_algid);
|
||||||
|
fclose (pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//extra safeguards due to sync issues with NXDN
|
||||||
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||||
|
|
||||||
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
|
|
||||||
|
//reset dmr blocks
|
||||||
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
|
//zero out additional items
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
state->payload_miN = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
|
||||||
|
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||||||
|
//RIGCTL
|
||||||
|
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
//drop all items (failsafe)
|
||||||
|
noCarrier(opts, state);
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
if (opts->p25_trunk == 1 && opts->audio_in_type == 3)
|
||||||
|
{
|
||||||
|
//drop all items (failsafe)
|
||||||
|
noCarrier(opts, state);
|
||||||
|
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 0)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->lasttgR != 0 && opts->frame_provoice != 1 && c == 64) //SHIFT+'2' key (@ at sign), lockout slot 2 tdma tgR from tuning/playback during session
|
||||||
|
{
|
||||||
|
state->group_array[state->group_tally].groupNumber = state->lasttgR;
|
||||||
|
sprintf (state->group_array[state->group_tally].groupMode, "%s", "B");
|
||||||
|
sprintf (state->group_array[state->group_tally].groupName, "%s", "LOCKOUT");
|
||||||
|
state->group_tally++;
|
||||||
|
|
||||||
|
sprintf (state->event_history_s[1].Event_History_Items[0].internal_str, "Target: %d; has been locked out; User Lock Out.", state->lasttgR);
|
||||||
|
watchdog_event_current(opts, state, 1);
|
||||||
|
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||||
|
|
||||||
|
//if we have an opened group file, let's write a group lock out into it to make it permanent
|
||||||
|
if (opts->group_in_file[0] != 0) //file is available
|
||||||
|
{
|
||||||
|
FILE * pFile; //file pointer
|
||||||
|
//open file by name that is supplied in the ncurses terminal, or cli
|
||||||
|
pFile = fopen (opts->group_in_file, "a");
|
||||||
|
fprintf (pFile, "%d,B,LOCKOUT,%02X\n", state->lasttgR, state->payload_algidR);
|
||||||
|
fclose (pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//extra safeguards due to sync issues with NXDN
|
||||||
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||||
|
|
||||||
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
|
|
||||||
|
//reset dmr blocks
|
||||||
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
|
//zero out additional items
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
state->payload_miN = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
|
||||||
|
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||||||
|
//RIGCTL
|
||||||
|
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
//drop all items (failsafe)
|
||||||
|
noCarrier(opts, state);
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
if (opts->p25_trunk == 1 && opts->audio_in_type == 3)
|
||||||
|
{
|
||||||
|
//drop all items (failsafe)
|
||||||
|
noCarrier(opts, state);
|
||||||
|
rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 0)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->p25_trunk == 1 && c == 119) //'w' key, toggle white list/black list mode
|
||||||
|
{
|
||||||
|
if (opts->trunk_use_allow_list == 1) opts->trunk_use_allow_list = 0;
|
||||||
|
else opts->trunk_use_allow_list = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->p25_trunk == 1 && c == 117) //'u' key, toggle tune private calls
|
||||||
|
{
|
||||||
|
if (opts->trunk_tune_private_calls == 1) opts->trunk_tune_private_calls = 0;
|
||||||
|
else opts->trunk_tune_private_calls = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->p25_trunk == 1 && c == 100) //'d' key, toggle tune data calls
|
||||||
|
{
|
||||||
|
if (opts->trunk_tune_data_calls == 1) opts->trunk_tune_data_calls = 0;
|
||||||
|
else opts->trunk_tune_data_calls = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->p25_trunk == 1 && c == 101) //'e' key, toggle tune enc calls (P25 only on certain grants)
|
||||||
|
{
|
||||||
|
if (opts->trunk_tune_enc_calls == 1) opts->trunk_tune_enc_calls = 0;
|
||||||
|
else opts->trunk_tune_enc_calls = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
|
||||||
|
{
|
||||||
|
if (opts->trunk_tune_group_calls == 1) opts->trunk_tune_group_calls = 0;
|
||||||
|
else opts->trunk_tune_group_calls = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
|
||||||
|
{
|
||||||
|
if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1;
|
||||||
|
else opts->aggressive_framesync = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
|
||||||
|
{
|
||||||
|
//dmr trunking/ncurses stuff
|
||||||
|
state->dmr_rest_channel = -1; //init on -1
|
||||||
|
state->dmr_mfid = -1; //
|
||||||
|
|
||||||
|
//dmr mfid branding and site parms
|
||||||
|
sprintf(state->dmr_branding_sub, "%s", "");
|
||||||
|
sprintf(state->dmr_branding, "%s", "");
|
||||||
|
sprintf (state->dmr_site_parms, "%s", "");
|
||||||
|
|
||||||
|
//DMR Location Area - DMRLA B***S***
|
||||||
|
opts->dmr_dmrla_is_set = 0;
|
||||||
|
opts->dmr_dmrla_n = 0;
|
||||||
|
|
||||||
|
//reset NXDN info
|
||||||
|
state->nxdn_location_site_code = 0;
|
||||||
|
state->nxdn_location_sys_code = 0;
|
||||||
|
sprintf (state->nxdn_location_category, "%s", " ");
|
||||||
|
|
||||||
|
state->nxdn_last_ran = -1; //0
|
||||||
|
state->nxdn_ran = 0; //0
|
||||||
|
|
||||||
|
state->nxdn_rcn = 0;
|
||||||
|
state->nxdn_base_freq = 0;
|
||||||
|
state->nxdn_step = 0;
|
||||||
|
state->nxdn_bw = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Debug/Troubleshooting Option
|
||||||
|
if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z)
|
||||||
|
{
|
||||||
|
// opts->p25_is_tuned = 0;
|
||||||
|
state->last_cc_sync_time = 0;
|
||||||
|
state->last_vc_sync_time = 0;
|
||||||
|
noCarrier(opts, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 93) //']' key - increment event history indexer
|
||||||
|
{
|
||||||
|
state->eh_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 91) //'[' key - decrement event history indexer
|
||||||
|
{
|
||||||
|
state->eh_index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 92) //'\' key - toggle events for slot displayed, and reset eh_index
|
||||||
|
{
|
||||||
|
state->eh_slot ^= 1;
|
||||||
|
state->eh_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//attempt retry to TCP Audio server
|
||||||
|
if (c == 56) // '8' key, try audio in type 8 (TCP Audio Server connection) using defaults OR whatever the user last specified
|
||||||
|
{
|
||||||
|
|
||||||
|
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
|
||||||
|
if (opts->tcp_sockfd != 0)
|
||||||
|
{
|
||||||
|
//reset audio input stream
|
||||||
|
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
|
||||||
|
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
|
||||||
|
opts->audio_in_file_info->channels=1;
|
||||||
|
opts->audio_in_file_info->seekable=0;
|
||||||
|
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
|
||||||
|
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
|
||||||
|
|
||||||
|
if(opts->tcp_file_in == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error, couldn't Connect to TCP with libsndfile: %s\n", sf_strerror(NULL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//close pulse input if it is currently open
|
||||||
|
if (opts->audio_in_type == 0) closePulseInput(opts);
|
||||||
|
fprintf (stderr, "TCP Socket Connected Successfully.\n");
|
||||||
|
opts->audio_in_type = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else fprintf (stderr, "TCP Socket Connection Error.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 57) //'9' key, try rigctl connection with default values
|
||||||
|
{
|
||||||
|
//use same or last specified host for TCP audio sink for connection
|
||||||
|
memcpy (opts->rigctlhostname, opts->tcp_hostname, sizeof (opts->rigctlhostname) );
|
||||||
|
opts->rigctl_sockfd = Connect(opts->rigctlhostname, opts->rigctlportno);
|
||||||
|
if (opts->rigctl_sockfd != 0) opts->use_rigctl = 1;
|
||||||
|
else opts->use_rigctl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if trunking and user wants to just go back to the control channel and skip this call
|
||||||
|
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && c == 67) //Capital C key - Return to CC
|
||||||
|
{
|
||||||
|
|
||||||
|
//extra safeguards due to sync issues with NXDN
|
||||||
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||||
|
|
||||||
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
|
|
||||||
|
//reset dmr blocks
|
||||||
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
|
//zero out additional items
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
state->payload_miN = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
|
||||||
|
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||||||
|
//RIGCTL
|
||||||
|
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 0)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 1)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 8;
|
||||||
|
state->symbolCenter = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "\n User Activated Return to CC; \n ");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//if trunking or scanning, manually cycle forward through channels loaded (can be run without trunking or scanning enabled)
|
||||||
|
if ( (opts->use_rigctl == 1 || opts->audio_in_type == 3) && c == 76) //Capital L key - Cycle Channels Forward
|
||||||
|
{
|
||||||
|
|
||||||
|
//extra safeguards due to sync issues with NXDN
|
||||||
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||||
|
|
||||||
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
|
|
||||||
|
//reset dmr blocks
|
||||||
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
|
//zero out additional items
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
state->payload_miN = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
|
||||||
|
//just copy and pasted the cycle logic for CC/signal hunting on no sync
|
||||||
|
if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list
|
||||||
|
{
|
||||||
|
state->lcn_freq_roll = 0; //reset to zero
|
||||||
|
}
|
||||||
|
|
||||||
|
//roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc
|
||||||
|
if (state->lcn_freq_roll != 0)
|
||||||
|
{
|
||||||
|
if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll])
|
||||||
|
{
|
||||||
|
state->lcn_freq_roll++;
|
||||||
|
//check roll again if greater than expected, then go back to zero
|
||||||
|
if (state->lcn_freq_roll >= state->lcn_freq_count)
|
||||||
|
{
|
||||||
|
state->lcn_freq_roll = 0; //reset to zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check that we have a non zero value first, then tune next frequency
|
||||||
|
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
|
||||||
|
{
|
||||||
|
//rigctl
|
||||||
|
if (opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||||
|
}
|
||||||
|
//rtl
|
||||||
|
if (opts->audio_in_type == 3)
|
||||||
|
{
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf (stderr, "\n User Activated Channel Cycle;");
|
||||||
|
fprintf (stderr, " Tuning to Frequency: %.06lf MHz\n",
|
||||||
|
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
|
||||||
|
|
||||||
|
}
|
||||||
|
state->lcn_freq_roll++;
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
|
||||||
|
//may need to test to see if we want to do the conditional below or not for symbol rate flipping
|
||||||
|
|
||||||
|
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 0)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 1)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 8;
|
||||||
|
state->symbolCenter = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 118 && opts->audio_in_type == 3) //'v' key, cycle rtl volume multiplier, when active
|
||||||
|
{
|
||||||
|
if (opts->rtl_volume_multiplier == 1 || opts->rtl_volume_multiplier == 2) opts->rtl_volume_multiplier++;
|
||||||
|
else opts->rtl_volume_multiplier = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 86) // 'V' Key, toggle LPF
|
||||||
|
{
|
||||||
|
if (opts->use_lpf == 0) opts->use_lpf = 1;
|
||||||
|
else opts->use_lpf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 66) // 'B' Key, toggle HPF
|
||||||
|
{
|
||||||
|
if (opts->use_hpf == 0) opts->use_hpf = 1;
|
||||||
|
else opts->use_hpf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 78) // 'N' Key, toggle PBF
|
||||||
|
{
|
||||||
|
if (opts->use_pbf == 0) opts->use_pbf = 1;
|
||||||
|
else opts->use_pbf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 72) // 'H' Key, toggle HPF on digital
|
||||||
|
{
|
||||||
|
if (opts->use_hpf_d == 0) opts->use_hpf_d = 1;
|
||||||
|
else opts->use_hpf_d = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(opts->frame_provoice == 1 && c == 65) //'A' Key, toggle ESK mask 0xA0
|
||||||
|
{
|
||||||
|
if (state->esk_mask == 0) state->esk_mask = 0xA0;
|
||||||
|
else state->esk_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(opts->frame_provoice == 1 && c == 83) //'S' Key, toggle STD or EA mode and reset
|
||||||
|
{
|
||||||
|
if (state->ea_mode == -1) state->ea_mode = 0;
|
||||||
|
else if (state->ea_mode == 0) state->ea_mode = 1;
|
||||||
|
else state->ea_mode = 0;
|
||||||
|
|
||||||
|
//reset -- test to make sure these don't do weird things when reset
|
||||||
|
state->edacs_site_id = 0;
|
||||||
|
state->edacs_lcn_count = 0;
|
||||||
|
state->edacs_cc_lcn = 0;
|
||||||
|
state->edacs_vc_lcn = 0;
|
||||||
|
state->edacs_tuned_lcn = -1;
|
||||||
|
state->edacs_vc_call_type = 0;
|
||||||
|
state->p25_cc_freq = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//RTL PPM Manual Adjustment
|
||||||
|
if (c == 125)
|
||||||
|
opts->rtlsdr_ppm_error++;
|
||||||
|
|
||||||
|
if (c == 123)
|
||||||
|
opts->rtlsdr_ppm_error--;
|
||||||
|
|
||||||
|
//anything with an entry box will need the inputs and outputs stopped first
|
||||||
|
//so probably just write a function to handle c input, and when c = certain values
|
||||||
|
//needing an entry box, then stop all of those
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} //end ncursesPrinter
|
||||||
1631
src/dsd_ncurses_menu.c
Normal file
1631
src/dsd_ncurses_menu.c
Normal file
File diff suppressed because it is too large
Load Diff
1712
src/dsd_ncurses_printer.c
Normal file
1712
src/dsd_ncurses_printer.c
Normal file
File diff suppressed because it is too large
Load Diff
150
src/dsd_rigctl.c
150
src/dsd_rigctl.c
@@ -31,6 +31,7 @@ void error(char *msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in address;
|
struct sockaddr_in address;
|
||||||
|
struct sockaddr_in addressA;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Connect
|
// Connect
|
||||||
@@ -133,7 +134,7 @@ bool SetFreq(int sockfd, long int freq)
|
|||||||
Send(sockfd, buf);
|
Send(sockfd, buf);
|
||||||
Recv(sockfd, buf);
|
Recv(sockfd, buf);
|
||||||
|
|
||||||
if (strcmp(buf, "RPRT 1") == 0 )
|
if (strcmp(buf, "RPRT 1\n") == 0 ) //sdr++ has a linebreak here, is that in all versions of the protocol?
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -143,11 +144,19 @@ bool SetModulation(int sockfd, int bandwidth)
|
|||||||
{
|
{
|
||||||
char buf[BUFSIZE];
|
char buf[BUFSIZE];
|
||||||
//the bandwidth is now a user/system based configurable variable
|
//the bandwidth is now a user/system based configurable variable
|
||||||
sprintf (buf, "M FM %d\n", bandwidth);
|
sprintf (buf, "M NFM %d\n", bandwidth); //SDR++ has changed the token from FM to NFM, even if Ryzerth fixes it later, users may still have an older version
|
||||||
Send(sockfd, buf);
|
Send(sockfd, buf);
|
||||||
Recv(sockfd, buf);
|
Recv(sockfd, buf);
|
||||||
|
|
||||||
if (strcmp(buf, "RPRT 1") == 0 )
|
//if it fails the first time, send the other token instead
|
||||||
|
if (strcmp(buf, "RPRT 1\n") == 0 ) //sdr++ has a linebreak here, is that in all versions of the protocol?
|
||||||
|
{
|
||||||
|
sprintf (buf, "M FM %d\n", bandwidth); //anything not SDR++
|
||||||
|
Send(sockfd, buf);
|
||||||
|
Recv(sockfd, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(buf, "RPRT 1\n") == 0 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -250,6 +259,12 @@ int UDPBind (char *hostname, int portno)
|
|||||||
perror("ERROR on binding UDP Port");
|
perror("ERROR on binding UDP Port");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set these for non blocking when no samples to read
|
||||||
|
struct timeval read_timeout;
|
||||||
|
read_timeout.tv_sec = 0;
|
||||||
|
read_timeout.tv_usec = 10;
|
||||||
|
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout);
|
||||||
|
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +298,7 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
|||||||
close (handle); //close socket after sending.
|
close (handle); //close socket after sending.
|
||||||
}
|
}
|
||||||
|
|
||||||
int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
UNUSED(state);
|
||||||
size_t err = 0;
|
size_t err = 0;
|
||||||
@@ -291,16 +306,16 @@ int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * d
|
|||||||
//listen with:
|
//listen with:
|
||||||
|
|
||||||
//short 8k/2
|
//short 8k/2
|
||||||
//socat stdio udp-listen:23456 | play --buffer 320*2 -q -b 16 -r 8000 -c2 -t s16 -
|
//socat stdio udp-listen:23456 | play --buffer 640 -q -b 16 -r 8000 -c2 -t s16 -
|
||||||
|
|
||||||
//short 8k/1
|
//short 8k/1
|
||||||
//socat stdio udp-listen:23456 | play --buffer 160*2 -q -b 16 -r 48000 -c2 -t s16 -
|
//socat stdio udp-listen:23456 | play --buffer 320 -q -b 16 -r 8000 -c1 -t s16 -
|
||||||
|
|
||||||
//float 8k/2
|
//float 8k/2
|
||||||
//socat stdio udp-listen:23456 | play --buffer 320*4 -q -e float -b 32 -r 8000 -c2 -t f32 -
|
//socat stdio udp-listen:23456 | play --buffer 1280 -q -e float -b 32 -r 8000 -c2 -t f32 -
|
||||||
|
|
||||||
//float 8k/1
|
//float 8k/1
|
||||||
//socat stdio udp-listen:23456 | play --buffer 160*4 -q -e float -b 32 -r 8000 -c1 -t f32 -
|
//socat stdio udp-listen:23456 | play --buffer 640 -q -e float -b 32 -r 8000 -c1 -t f32 -
|
||||||
|
|
||||||
//send audio or data to socket
|
//send audio or data to socket
|
||||||
err = sendto(opts->udp_sockfd, data, nsam, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
err = sendto(opts->udp_sockfd, data, nsam, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||||
@@ -308,6 +323,23 @@ int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * d
|
|||||||
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Analog UDP port on +2 of normal open socket
|
||||||
|
void udp_socket_blasterA(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
size_t err = 0;
|
||||||
|
|
||||||
|
//listen with:
|
||||||
|
|
||||||
|
//short 48k/1
|
||||||
|
//socat stdio udp-listen:23456 | play --buffer 1920 -q -b 16 -r 48000 -c1 -t s16 -
|
||||||
|
|
||||||
|
//send audio or data to socket
|
||||||
|
err = sendto(opts->udp_sockfdA, data, nsam, 0, (const struct sockaddr * ) & addressA, sizeof(struct sockaddr_in));
|
||||||
|
if (err < 0) fprintf (stderr, "\n UDP SENDTO ERR %ld", err); //return value here is size_t number of characters sent, or -1 for failure
|
||||||
|
if (err < nsam) fprintf (stderr, "\n UDP Underflow %ld", err); //I'm not even sure if this is possible
|
||||||
|
}
|
||||||
|
|
||||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
||||||
{
|
{
|
||||||
UNUSED(state);
|
UNUSED(state);
|
||||||
@@ -345,4 +377,106 @@ int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int udp_socket_connectA(dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
UNUSED(state);
|
||||||
|
|
||||||
|
long int err = 0;
|
||||||
|
err = opts->udp_sockfdA = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " UDP Socket Error %ld\n", err);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't think this is needed, but doesn't seem to hurt to keep it here either
|
||||||
|
int broadcastEnable = 1;
|
||||||
|
err = setsockopt(opts->udp_sockfdA, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((char * ) & addressA, 0, sizeof(addressA));
|
||||||
|
addressA.sin_family = AF_INET;
|
||||||
|
err = addressA.sin_addr.s_addr = inet_addr(opts->udp_hostname);
|
||||||
|
if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs
|
||||||
|
{
|
||||||
|
fprintf (stderr, " UDP inet_addr Error %ld\n", err);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
addressA.sin_port = htons(opts->udp_portno+2); //plus 2 to current port assignment for the analog port value
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, " UDP htons Error %ld\n", err);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void return_to_cc (dsd_opts * opts, dsd_state * state)
|
||||||
|
{
|
||||||
|
//extra safeguards due to sync issues with NXDN
|
||||||
|
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
|
||||||
|
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
|
||||||
|
|
||||||
|
memset (state->active_channel, 0, sizeof(state->active_channel));
|
||||||
|
|
||||||
|
//reset dmr blocks
|
||||||
|
dmr_reset_blocks (opts, state);
|
||||||
|
|
||||||
|
//zero out additional items
|
||||||
|
state->lasttg = 0;
|
||||||
|
state->lasttgR = 0;
|
||||||
|
state->lastsrc = 0;
|
||||||
|
state->lastsrcR = 0;
|
||||||
|
state->gi[0] = -1;
|
||||||
|
state->gi[1] = -1;
|
||||||
|
state->payload_algid = 0;
|
||||||
|
state->payload_algidR = 0;
|
||||||
|
state->payload_keyid = 0;
|
||||||
|
state->payload_keyidR = 0;
|
||||||
|
state->payload_mi = 0;
|
||||||
|
state->payload_miR = 0;
|
||||||
|
state->payload_miP = 0;
|
||||||
|
state->payload_miN = 0;
|
||||||
|
opts->p25_is_tuned = 0;
|
||||||
|
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||||
|
|
||||||
|
//tune back to the control channel -- NOTE: Doesn't work correctly on EDACS Analog Voice
|
||||||
|
//RIGCTL
|
||||||
|
if (opts->p25_trunk == 1 && opts->use_rigctl == 1)
|
||||||
|
{
|
||||||
|
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
|
||||||
|
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtl
|
||||||
|
#ifdef USE_RTLSDR
|
||||||
|
if (opts->p25_trunk == 1 && opts->audio_in_type == 3) rtl_dev_tune (opts, state->p25_cc_freq);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state->last_cc_sync_time = time(NULL);
|
||||||
|
|
||||||
|
//if P25p2 VCH and going back to P25p1 CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 0)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 10;
|
||||||
|
state->symbolCenter = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if P25p1 Data Revert on P25p2 TDMA CC, flip symbolrate
|
||||||
|
if (state->p25_cc_is_tdma == 1)
|
||||||
|
{
|
||||||
|
state->samplesPerSymbol = 8;
|
||||||
|
state->symbolCenter = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf (stderr, "\n User Activated Return to CC; \n ");
|
||||||
}
|
}
|
||||||
|
|||||||
133
src/dsd_symbol.c
133
src/dsd_symbol.c
@@ -17,29 +17,6 @@
|
|||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len
|
|
||||||
{
|
|
||||||
|
|
||||||
int i;
|
|
||||||
long int rms;
|
|
||||||
long p, t, s;
|
|
||||||
double dc, err;
|
|
||||||
|
|
||||||
p = t = 0L;
|
|
||||||
for (i=0; i<len; i+=step) {
|
|
||||||
s = (long)samples[i];
|
|
||||||
t += s;
|
|
||||||
p += s * s;
|
|
||||||
}
|
|
||||||
/* correct for dc offset in squares */
|
|
||||||
dc = (double)(t*step) / (double)len;
|
|
||||||
err = t * 2 * dc - dc * dc * len;
|
|
||||||
|
|
||||||
rms = (long int)sqrt((p-err) / len);
|
|
||||||
if (rms < 0) rms = 150;
|
|
||||||
return rms;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||||
{
|
{
|
||||||
@@ -156,6 +133,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
cleanupAndExit(opts, state);
|
cleanupAndExit(opts, state);
|
||||||
//update root means square power level
|
//update root means square power level
|
||||||
opts->rtl_rms = rtl_return_rms();
|
opts->rtl_rms = rtl_return_rms();
|
||||||
|
sample *= opts->rtl_volume_multiplier;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -163,7 +141,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
//tcp socket input from SDR++ -- now with 1 retry if connection is broken
|
//tcp socket input from SDR++ -- now with 1 retry if connection is broken
|
||||||
else if (opts->audio_in_type == 8)
|
else if (opts->audio_in_type == 8)
|
||||||
{
|
{
|
||||||
#ifdef AERO_BUILD
|
#ifdef __CYGWIN__
|
||||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
if(result == 0) {
|
if(result == 0) {
|
||||||
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
||||||
@@ -222,6 +200,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
#else
|
#else
|
||||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
if(result == 0) {
|
if(result == 0) {
|
||||||
|
TCP_RETRY:
|
||||||
|
if (exitflag == 1) cleanupAndExit(opts, state); //needed to break the loop on ctrl+c
|
||||||
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
fprintf (stderr, "\nConnection to TCP Server Interrupted. Trying again in 3 seconds.\n");
|
||||||
sample = 0;
|
sample = 0;
|
||||||
sf_close(opts->tcp_file_in); //close current connection on this end
|
sf_close(opts->tcp_file_in); //close current connection on this end
|
||||||
@@ -246,7 +226,11 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
}
|
}
|
||||||
else fprintf (stderr, "TCP Socket Reconnected Successfully.\n");
|
else fprintf (stderr, "TCP Socket Reconnected Successfully.\n");
|
||||||
}
|
}
|
||||||
else fprintf (stderr, "TCP Socket Connection Error.\n");
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "TCP Socket Connection Error.\n");
|
||||||
|
if (opts->frame_m17 == 1) goto TCP_RETRY; //if using m17 encoder/decoder, just keep looping to keep alive
|
||||||
|
}
|
||||||
|
|
||||||
//now retry reading sample
|
//now retry reading sample
|
||||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||||
@@ -264,16 +248,17 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//BUG REPORT: 1. DMR Simplex doesn't work with raw wav files. 2. Using the monitor w/ wav file saving may produce undecodable wav files.
|
||||||
//reworked a bit to allow raw audio wav file saving without the monitoring poriton active
|
//reworked a bit to allow raw audio wav file saving without the monitoring poriton active
|
||||||
if (have_sync == 0)
|
if (have_sync == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
//do an extra checkfor carrier signal so that random raw audio spurts don't play during decoding
|
//do an extra checkfor carrier signal so that random raw audio spurts don't play during decoding
|
||||||
if ( (state->carrier == 1) && ((time(NULL) - state->last_vc_sync_time) < 2))
|
// if ( (state->carrier == 1) && ((time(NULL) - state->last_vc_sync_time) < 2)) /This probably doesn't work correctly since we update time check when playing raw audio
|
||||||
{
|
// {
|
||||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
// memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||||
state->analog_sample_counter = 0;
|
// state->analog_sample_counter = 0;
|
||||||
}
|
// } //This is the root cause of issue listed above, will evaluate further at a later time for a more elegant solution, or determine if anything is negatively impacted by removing this
|
||||||
|
|
||||||
//sanity check to prevent an overflow
|
//sanity check to prevent an overflow
|
||||||
if (state->analog_sample_counter > 959)
|
if (state->analog_sample_counter > 959)
|
||||||
@@ -287,21 +272,46 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
||||||
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||||
|
|
||||||
//debug
|
//raw wav file saving -- only write when not NXDN, dPMR, or M17 due to noise that can cause tons of false positives when no sync
|
||||||
// opts->rtl_rms = 101;
|
if (opts->wav_out_raw != NULL && opts->frame_nxdn48 == 0 && opts->frame_nxdn96 == 0 && opts->frame_dpmr == 0 && opts->frame_m17 == 0)
|
||||||
|
{
|
||||||
|
sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
||||||
|
sf_write_sync (opts->wav_out_raw);
|
||||||
|
}
|
||||||
|
|
||||||
//make it a little quieter
|
//low pass filter
|
||||||
// for (int x = 0; x < 960; x++)
|
if (opts->use_lpf == 1)
|
||||||
// state->analog_out[x] /= 4;
|
lpf(state, state->analog_out, 960);
|
||||||
|
|
||||||
|
//high pass filter
|
||||||
|
if (opts->use_hpf == 1)
|
||||||
|
hpf (state, state->analog_out, 960);
|
||||||
|
|
||||||
|
//pass band filter
|
||||||
|
if (opts->use_pbf == 1)
|
||||||
|
pbf(state, state->analog_out, 960);
|
||||||
|
|
||||||
|
//manual gain control
|
||||||
|
if (opts->audio_gainA > 0.0f)
|
||||||
|
analog_gain (opts, state, state->analog_out, 960);
|
||||||
|
|
||||||
|
//automatic gain control
|
||||||
|
else
|
||||||
|
agsm(opts, state, state->analog_out, 960);
|
||||||
|
|
||||||
|
//Running RMS after filtering does remove the analog spike from the RMS value
|
||||||
|
//but noise floor noise will still produce higher values
|
||||||
|
// if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
|
||||||
|
// opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||||
|
|
||||||
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
|
||||||
if ( (opts->rtl_rms > opts->rtl_squelch_level) && (opts->monitor_input_audio == 1) )
|
if ( (opts->rtl_rms > opts->rtl_squelch_level) && opts->monitor_input_audio == 1 && state->carrier == 0 ) //added carrier check here in lieu of disabling it above
|
||||||
{
|
{
|
||||||
if (opts->audio_out_type == 0)
|
if (opts->audio_out_type == 0)
|
||||||
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
||||||
|
|
||||||
if (opts->audio_out_type == 8)
|
if (opts->audio_out_type == 8)
|
||||||
udp_socket_blaster (opts, state, 960*2, state->analog_out);
|
udp_socket_blasterA (opts, state, 960*2, state->analog_out);
|
||||||
|
|
||||||
//NOTE: Worked okay earlier in Cygwin, so should be fine -- can only operate at 48k1, else slow mode lag
|
//NOTE: Worked okay earlier in Cygwin, so should be fine -- can only operate at 48k1, else slow mode lag
|
||||||
|
|
||||||
@@ -322,12 +332,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
state->last_vc_sync_time = time(NULL);
|
state->last_vc_sync_time = time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//raw wav file saving -- only write when not NXDN, dPMR, or M17 due to noise that can cause tons of false positives when no sync
|
//raw wav file saving -- save the WAV file samples before we apply filtering to them
|
||||||
if (opts->wav_out_raw != NULL && opts->frame_nxdn48 == 0 && opts->frame_nxdn96 == 0 && opts->frame_dpmr == 0 && opts->frame_m17 == 0)
|
// if (opts->wav_out_raw != NULL && opts->frame_nxdn48 == 0 && opts->frame_nxdn96 == 0 && opts->frame_dpmr == 0 && opts->frame_m17 == 0)
|
||||||
{
|
// {
|
||||||
sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
// sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
||||||
sf_write_sync (opts->wav_out_raw);
|
// sf_write_sync (opts->wav_out_raw);
|
||||||
}
|
// }
|
||||||
|
|
||||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||||
state->analog_sample_counter = 0;
|
state->analog_sample_counter = 0;
|
||||||
@@ -367,7 +377,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
sample = dmr_filter(sample);
|
sample = dmr_filter(sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||state->lastsynctype == 16 || state->lastsynctype == 17)
|
else if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17 ||
|
||||||
|
state->lastsynctype == 86 || state->lastsynctype == 87 || state->lastsynctype == 98 || state->lastsynctype == 99)
|
||||||
{
|
{
|
||||||
sample = m17_filter(sample);
|
sample = m17_filter(sample);
|
||||||
}
|
}
|
||||||
@@ -616,13 +627,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//test throttle on wav input files
|
//read dibit capture bin files
|
||||||
if (opts->audio_in_type == 2)
|
|
||||||
{
|
|
||||||
if (state->use_throttle == 1) usleep(.003); //very environment specific, tuning to cygwin
|
|
||||||
}
|
|
||||||
|
|
||||||
//read op25/fme symbol bin files
|
|
||||||
if (opts->audio_in_type == 4)
|
if (opts->audio_in_type == 4)
|
||||||
{
|
{
|
||||||
//use fopen and read in a symbol, check op25 for clues
|
//use fopen and read in a symbol, check op25 for clues
|
||||||
@@ -634,21 +639,21 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
state->symbolc = fgetc(opts->symbolfile);
|
state->symbolc = fgetc(opts->symbolfile);
|
||||||
|
|
||||||
//experimental throttle
|
|
||||||
if (state->use_throttle == 1)
|
|
||||||
{
|
|
||||||
// useconds_t stime = state->symbol_throttle;
|
|
||||||
// usleep(stime);
|
|
||||||
usleep(.003); //very environment specific, tuning to cygwin
|
|
||||||
}
|
|
||||||
//fprintf(stderr, "%d", state->symbolc);
|
//fprintf(stderr, "%d", state->symbolc);
|
||||||
if( feof(opts->symbolfile) )
|
if( feof(opts->symbolfile) )
|
||||||
{
|
{
|
||||||
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||||
fclose(opts->symbolfile);
|
fclose(opts->symbolfile);
|
||||||
fprintf (stderr, "\nEnd of %s\n", opts->audio_in_dev);
|
fprintf (stderr, "\nEnd of %s\n", opts->audio_in_dev);
|
||||||
|
//in debug mode, re-run .bin files over and over (look for memory leaks, etc)
|
||||||
|
if (state->debug_mode == 1)
|
||||||
|
{
|
||||||
|
opts->symbolfile = NULL;
|
||||||
|
opts->symbolfile = fopen(opts->audio_in_dev, "r");
|
||||||
|
opts->audio_in_type = 4; //symbol capture bin files
|
||||||
|
}
|
||||||
//open pulse input if we are pulse output AND using ncurses terminal
|
//open pulse input if we are pulse output AND using ncurses terminal
|
||||||
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
else if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
|
||||||
{
|
{
|
||||||
opts->audio_in_type = 0; //set input type
|
opts->audio_in_type = 0; //set input type
|
||||||
openPulseInput(opts); //open pulse input
|
openPulseInput(opts); //open pulse input
|
||||||
@@ -695,6 +700,16 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//.raw or .sym float symbol files
|
||||||
|
if (opts->audio_in_type == 44)
|
||||||
|
{
|
||||||
|
float float_symbol = 0.0f;
|
||||||
|
fread (&float_symbol, sizeof(float), 1, opts->symbolfile); //sizeof(float) is 4 (usually)
|
||||||
|
if ( feof(opts->symbolfile) ) exitflag = 1; //end of file, exit
|
||||||
|
// float_symbol = -float_symbol; //inversion
|
||||||
|
symbol = (int)float_symbol * (int)10000;
|
||||||
|
}
|
||||||
|
|
||||||
state->symbolcnt++;
|
state->symbolcnt++;
|
||||||
return (symbol);
|
return (symbol);
|
||||||
}
|
}
|
||||||
|
|||||||
98
src/dsd_time.c
Normal file
98
src/dsd_time.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/*-------------------------------------------------------------------------------
|
||||||
|
* dsd_time.c
|
||||||
|
* Time and Date Functions
|
||||||
|
*
|
||||||
|
* LWVMOBILE
|
||||||
|
* 2024-04 DSD-FME Florida Man Edition
|
||||||
|
*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//TODO: Make sure everything still works as intended, every free(timestr) has a NULL check first,
|
||||||
|
//make sure no other loose or random time functions embedded in other files or functions, etc
|
||||||
|
|
||||||
|
#include "dsd.h"
|
||||||
|
|
||||||
|
//get HHmmss timestamp no colon (file operations)
|
||||||
|
char * getTime()
|
||||||
|
{
|
||||||
|
char * curr = calloc(7, sizeof(char));
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr,"%02d%02d%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get HH:mm:ss timestamp with colon (Sync/Console Display)
|
||||||
|
char * getTimeC()
|
||||||
|
{
|
||||||
|
char * curr = calloc(9, sizeof(char));
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr, "%02d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get HH:mm:ss timestamp with colon (Ncurses Call History)
|
||||||
|
char * getTimeN(time_t t)
|
||||||
|
{
|
||||||
|
char * curr = calloc(9, sizeof(char));
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr, "%02d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get YYYYMMDD without hyphen (file operations)
|
||||||
|
char * getDate()
|
||||||
|
{
|
||||||
|
char * curr = calloc(25, sizeof(char));
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr,"%04d%02d%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get YYYY-MM-DD with hyphen (Sync/Console Display)
|
||||||
|
char * getDateH()
|
||||||
|
{
|
||||||
|
char * curr = calloc(27, sizeof(char));
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr, "%04d-%02d-%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get YYYY/MM/DD with forward slash (LRRP files)
|
||||||
|
char * getDateS()
|
||||||
|
{
|
||||||
|
char * curr = calloc(27, sizeof(char));
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr, "%04d/%02d/%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get YYYY-MM-DD with hyphen (Ncurses Call History)
|
||||||
|
char * getDateN(time_t t)
|
||||||
|
{
|
||||||
|
char * curr = calloc(27, sizeof(char));
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr, "%04d-%02d-%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get HHmmss timestamp no colon (file operations)
|
||||||
|
char * getTimeF(time_t t)
|
||||||
|
{
|
||||||
|
char * curr = calloc(7, sizeof(char));
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr,"%02d%02d%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get YYYYMMDD without hyphen (file operations)
|
||||||
|
char * getDateF(time_t t)
|
||||||
|
{
|
||||||
|
char * curr = calloc(25, sizeof(char));
|
||||||
|
struct tm * ptm = localtime(& t);
|
||||||
|
sprintf(curr,"%04d%02d%02d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday);
|
||||||
|
return curr;
|
||||||
|
}
|
||||||
@@ -1,158 +1,47 @@
|
|||||||
/*
|
/*-------------------------------------------------------------------------------
|
||||||
* Copyright (C) 2010 DSD Author
|
* dsd_upsample.c
|
||||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
* Simplified 8k to 48k Upsample Functions
|
||||||
|
* Goodbye terrible ringing sound
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
*
|
||||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
* LWVMOBILE
|
||||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
* 2024-03 DSD-FME Florida Man Edition
|
||||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
*-----------------------------------------------------------------------------*/
|
||||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
||||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
* PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "dsd.h"
|
#include "dsd.h"
|
||||||
|
|
||||||
void
|
|
||||||
upsample (dsd_state * state, float invalue)
|
|
||||||
{
|
|
||||||
|
|
||||||
int i, j, sum;
|
|
||||||
float *outbuf1, c, d;
|
|
||||||
if (state->currentslot == 0 && state->dmr_stereo == 1)
|
|
||||||
{
|
|
||||||
outbuf1 = state->audio_out_float_buf_p;
|
|
||||||
}
|
|
||||||
if (state->currentslot == 1 && state->dmr_stereo == 1)
|
|
||||||
{
|
|
||||||
outbuf1 = state->audio_out_float_buf_pR;
|
|
||||||
}
|
|
||||||
if (state->dmr_stereo == 0)
|
|
||||||
{
|
|
||||||
outbuf1 = state->audio_out_float_buf_p;
|
|
||||||
}
|
|
||||||
//outbuf1 = state->audio_out_float_buf_p;
|
|
||||||
outbuf1--;
|
|
||||||
c = *outbuf1;
|
|
||||||
d = invalue;
|
|
||||||
// basic triangle interpolation
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834));
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668));
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5));
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
|
||||||
outbuf1++;
|
|
||||||
*outbuf1 = d;
|
|
||||||
outbuf1++;
|
|
||||||
|
|
||||||
//only if enabled, produces crackling/buzzing sounds when input type is not pulse audio (reason still unknown)
|
|
||||||
//also, could be improved to provide better audio in the future
|
|
||||||
if (state->audio_smoothing == 1)
|
|
||||||
{
|
|
||||||
if (state->currentslot == 1 && state->dmr_stereo == 1)
|
|
||||||
{
|
|
||||||
if (state->audio_out_idx2R > 24)
|
|
||||||
{
|
|
||||||
// smoothing
|
|
||||||
outbuf1 -= 16;
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
sum = 0;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
*outbuf1 = (sum / (float) 3);
|
|
||||||
outbuf1++;
|
|
||||||
}
|
|
||||||
outbuf1 -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state->currentslot == 0 && state->dmr_stereo == 1)
|
|
||||||
{
|
|
||||||
if (state->audio_out_idx2 > 24)
|
|
||||||
{
|
|
||||||
// smoothing
|
|
||||||
outbuf1 -= 16;
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
sum = 0;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
*outbuf1 = (sum / (float) 3);
|
|
||||||
outbuf1++;
|
|
||||||
}
|
|
||||||
outbuf1 -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state->dmr_stereo == 0)
|
|
||||||
{
|
|
||||||
if (state->audio_out_idx2 > 24)
|
|
||||||
{
|
|
||||||
// smoothing
|
|
||||||
outbuf1 -= 16;
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
sum = 0;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 += 2;
|
|
||||||
sum += (int)*outbuf1;
|
|
||||||
outbuf1 -= 2;
|
|
||||||
*outbuf1 = (sum / (float) 3);
|
|
||||||
outbuf1++;
|
|
||||||
}
|
|
||||||
outbuf1 -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//produce 6 short samples (48k) for every 1 short sample (8k)
|
//produce 6 short samples (48k) for every 1 short sample (8k)
|
||||||
void upsampleS (short invalue, short prev, short outbuf[6])
|
void upsampleS (short invalue, short prev, short outbuf[6])
|
||||||
{
|
{
|
||||||
|
UNUSED(prev);
|
||||||
float c, d;
|
for (int i = 0; i < 6; i++)
|
||||||
|
outbuf[i] = invalue;
|
||||||
c = prev;
|
}
|
||||||
d = invalue;
|
|
||||||
|
//legacy 6x simplified version for the float_buf_p
|
||||||
// basic triangle interpolation
|
void upsample (dsd_state * state, float invalue)
|
||||||
outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834));
|
{
|
||||||
outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668));
|
|
||||||
outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5));
|
float *outbuf1;
|
||||||
outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
if (state->currentslot == 0 && state->dmr_stereo == 1)
|
||||||
outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
outbuf1 = state->audio_out_float_buf_p;
|
||||||
outbuf[5] = c = d;
|
|
||||||
prev = d; //shift prev to the last d value for the next repitition
|
else if (state->currentslot == 1 && state->dmr_stereo == 1)
|
||||||
|
outbuf1 = state->audio_out_float_buf_pR;
|
||||||
|
|
||||||
|
else if (state->dmr_stereo == 0)
|
||||||
|
outbuf1 = state->audio_out_float_buf_p;
|
||||||
|
|
||||||
|
*outbuf1 = invalue;
|
||||||
|
outbuf1++;
|
||||||
|
*outbuf1 = invalue;
|
||||||
|
outbuf1++;
|
||||||
|
*outbuf1 = invalue;
|
||||||
|
outbuf1++;
|
||||||
|
*outbuf1 = invalue;
|
||||||
|
outbuf1++;
|
||||||
|
*outbuf1 = invalue;
|
||||||
|
outbuf1++;
|
||||||
|
*outbuf1 = invalue;
|
||||||
}
|
}
|
||||||
10
src/dstar.c
10
src/dstar.c
@@ -49,6 +49,10 @@ void processDSTAR(dsd_opts * opts, dsd_state * state)
|
|||||||
if (opts->use_ncurses_terminal == 1)
|
if (opts->use_ncurses_terminal == 1)
|
||||||
ncursesPrinter(opts, state);
|
ncursesPrinter(opts, state);
|
||||||
|
|
||||||
|
//slot 1
|
||||||
|
watchdog_event_history(opts, state, 0);
|
||||||
|
watchdog_event_current(opts, state, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
@@ -328,12 +332,14 @@ void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
|
|||||||
fprintf (stderr, "; ");
|
fprintf (stderr, "; ");
|
||||||
|
|
||||||
//Got the feeling nobody will actually ever see this message, but who knows
|
//Got the feeling nobody will actually ever see this message, but who knows
|
||||||
fprintf(stderr, "\n DEV NOTE: If you see this message, but incorrect lat/lon,\n please submit samples to https://github.com/lwvmobile/dsd-fme/issues/164 ");
|
// fprintf(stderr, "\n DEV NOTE: If you see this message, but incorrect lat/lon,\n please submit samples to https://github.com/lwvmobile/dsd-fme/issues/164 ");
|
||||||
|
|
||||||
SKIP: ; //do nothing
|
SKIP: ; //do nothing
|
||||||
|
|
||||||
//this seems to work okay with a few samples, but wouldn't be surprised if it broke down
|
//this seems to work okay with a few samples, but wouldn't be surprised if it broke down
|
||||||
//randomly on different users, depending on location and what else in in $$CRC
|
//randomly on different users, depending on location and what else in in $$CRC
|
||||||
|
|
||||||
|
sprintf (state->event_history_s[0].Event_History_Items[0].gps_s, "%s", state->dstar_gps);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -351,6 +357,7 @@ void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
|
|||||||
}
|
}
|
||||||
strt[59] = '\0';
|
strt[59] = '\0';
|
||||||
memcpy (state->dstar_txt, strt, sizeof(strt));
|
memcpy (state->dstar_txt, strt, sizeof(strt));
|
||||||
|
sprintf (state->event_history_s[0].Event_History_Items[0].text_message, "%s", state->dstar_txt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,6 +377,7 @@ void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
|
|||||||
}
|
}
|
||||||
strt[59] = '\0';
|
strt[59] = '\0';
|
||||||
memcpy (state->dstar_txt, strt, sizeof(strt));
|
memcpy (state->dstar_txt, strt, sizeof(strt));
|
||||||
|
sprintf (state->event_history_s[0].Event_History_Items[0].text_message, "%s", state->dstar_txt);
|
||||||
}
|
}
|
||||||
//anything else
|
//anything else
|
||||||
else //print entire thing
|
else //print entire thing
|
||||||
|
|||||||
@@ -436,10 +436,10 @@ decode_bch()
|
|||||||
d[u + 1] = alpha_to[s[u + 1]];
|
d[u + 1] = alpha_to[s[u + 1]];
|
||||||
else
|
else
|
||||||
d[u + 1] = 0;
|
d[u + 1] = 0;
|
||||||
for (i = 1; i <= l[u + 1]; i++)
|
for (i = 1; i <= l[u + 1]; i++)
|
||||||
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
||||||
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
||||||
+ index_of[elp[u + 1][i]]) % n];
|
+ index_of[elp[u + 1][i]]) % n];
|
||||||
/* put d[u+1] into index form */
|
/* put d[u+1] into index form */
|
||||||
d[u + 1] = index_of[d[u + 1]];
|
d[u + 1] = index_of[d[u + 1]];
|
||||||
}
|
}
|
||||||
|
|||||||
2250
src/edacs-fme.c
2250
src/edacs-fme.c
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@ int ez_rs28_facch (int payload[156], int parity[114])
|
|||||||
int i, j, k, b;
|
int i, j, k, b;
|
||||||
|
|
||||||
//init HB
|
//init HB
|
||||||
for (i = 0; i < 64; i++)
|
for (i = 0; i < (int)HB.size(); i++)
|
||||||
{
|
{
|
||||||
HB[i] = 0;
|
HB[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ int ez_rs28_sacch (int payload[180], int parity[132])
|
|||||||
int i, j, k, b;
|
int i, j, k, b;
|
||||||
|
|
||||||
//init HBS
|
//init HBS
|
||||||
for (i = 0; i < 64; i++)
|
for (i = 0; i < (int)HBS.size(); i++)
|
||||||
{
|
{
|
||||||
HBS[i] = 0;
|
HBS[i] = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user