mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
283 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ad9f4107c | ||
|
|
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
|
||||
*.ans
|
||||
*.patch
|
||||
*.zip
|
||||
result
|
||||
@@ -59,7 +59,7 @@ find_package(PulseAudio REQUIRED)
|
||||
find_package(CODEC2)
|
||||
|
||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${PULSEAUDIO_LIBRARY} ${CURSES_LIBRARY})
|
||||
|
||||
if(RTLSDR_FOUND)
|
||||
find_package(Threads)
|
||||
@@ -90,7 +90,9 @@ ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
|
||||
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
|
||||
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>)
|
||||
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>
|
||||
-Wmisleading-indentation -Wparentheses -Wunused-value -Wreturn-type
|
||||
-Wtautological-compare)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||
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.
|
||||
|
||||

|
||||
|
||||
|
||||
44
download-and-install-ubuntu2404lts.sh
Normal file
44
download-and-install-ubuntu2404lts.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
cdir=$(pwd)
|
||||
clear
|
||||
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer\n
|
||||
MBELib is considered a requirement on this build.
|
||||
You must view the Patent Notice prior to continuing.
|
||||
The Patent Notice can be found at the site below.
|
||||
https://github.com/lwvmobile/mbelib#readme
|
||||
Please confirm that you have viewed the patent notice by entering y below:\n\n"
|
||||
read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||
if [ "$ANSWER" = "y" ]; then
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncurses-dev libncurses6 libcodec2-dev
|
||||
chkitpp=$(sudo apt list libitpp-dev 2>&1|grep -ci "installed")
|
||||
if [ "$chkitpp" -lt "1" ];then
|
||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
||||
read -p "Press Enter to exit..." x
|
||||
exit 1
|
||||
fi
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd $cdir
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
#git checkout audio_work
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
else
|
||||
printf "\nSorry, you cannot build DSD-FME without acknowledging the Patent Notice.\nExiting...\n\n"
|
||||
exit 2
|
||||
fi
|
||||
BIN
dsd-fme2.png
BIN
dsd-fme2.png
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 393 KiB |
BIN
dsd-fme3.png
BIN
dsd-fme3.png
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 721 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!
|
||||
|
||||
`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)
|
||||
@@ -8,7 +8,11 @@
|
||||
-fa Legacy Auto (not recommended)
|
||||
-fi NXDN48
|
||||
-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.
|
||||
-f1 P25P1
|
||||
-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`
|
||||
|
||||
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 ###
|
||||
|
||||
@@ -74,7 +80,7 @@ Detailed Setup:
|
||||
|
||||
```
|
||||
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
|
||||
dev <num> RTL-SDR Device Index Number
|
||||
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||
@@ -82,9 +88,9 @@ RTL-SDR options:
|
||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
||||
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
|
||||
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
|
||||
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
|
||||
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
|
||||
|
||||
```
|
||||
|
||||
@@ -100,11 +106,11 @@ and in a second terminal tab, same folder, run
|
||||
|
||||
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`
|
||||
|
||||
@@ -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 - stop capturing symbol capture bin
|
||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||
s - stop playing symbol capture bin or wav input file
|
||||
s - stop playing symbol capture bin or wav input file (lower s)
|
||||
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)
|
||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
|
||||
@@ -196,8 +202,21 @@ Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
||||
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||
|
||||
k - Hold TG in Slot 1 or Conventional, or clear current hold (Testing/WIP: DMR T3 Only)
|
||||
l - Hold TG in Slot 2 on TDMA Systems, or clear current hold (Testing/WIP: DMR T3 Only)
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
v - Cycle RTL Input Volume Multiplier 1X, 2X, 3X (lower v)
|
||||
|
||||
```
|
||||
|
||||
@@ -269,4 +288,89 @@ Note: --buffer option in play is calculated by (channels * samples * sizeof(samp
|
||||
where samples is 160 for mono, 320 for stereo, and short samples are 2 and float samples are 4.
|
||||
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
|
||||
|
||||
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
|
||||
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
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -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
|
||||
chmod +x download-and-install.sh
|
||||
./download-and-install.sh
|
||||
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:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-Arch.sh
|
||||
chmod +x download-and-install-Arch.sh
|
||||
./download-and-install-Arch.sh
|
||||
sh download-and-install-Arch.sh
|
||||
```
|
||||
|
||||
### 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
|
||||
chmod +x download-and-install-nodeps.sh
|
||||
./download-and-install-nodeps.sh
|
||||
sh download-and-install-nodeps.sh
|
||||
```
|
||||
|
||||
## Manual Install
|
||||
@@ -38,7 +42,10 @@ Debian/Mint/Ubuntu/Pi
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
||||
#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 libitpp-dev 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 libitpp-dev libncurses-dev libncurses6 libcodec2-dev
|
||||
```
|
||||
|
||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||
|
||||
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 |
@@ -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 rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#EDACS/EDACS-EA Digital Only
|
||||
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
#EDACS Standard Network Analog and Digital
|
||||
#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 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
|
||||
#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 { };
|
||||
};
|
||||
};
|
||||
}
|
||||
222
include/dsd.h
222
include/dsd.h
@@ -61,8 +61,10 @@
|
||||
//OSS support
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
#include <pulse/pulseaudio.h> //PULSE AUDIO
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
#include <pulse/introspect.h> //PULSE AUDIO
|
||||
|
||||
#define SAMPLE_RATE_IN 48000 //48000
|
||||
#define SAMPLE_RATE_OUT 8000 //8000
|
||||
@@ -86,6 +88,44 @@
|
||||
|
||||
extern volatile uint8_t exitflag; //fix for issue #136
|
||||
|
||||
//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
|
||||
typedef struct
|
||||
{
|
||||
@@ -210,8 +250,8 @@ typedef struct
|
||||
SF_INFO *audio_in_file_info;
|
||||
|
||||
uint32_t rtlsdr_center_freq;
|
||||
int rtlsdr_ppm_error;
|
||||
int audio_in_type;
|
||||
int rtlsdr_ppm_error;
|
||||
int audio_in_type;
|
||||
char audio_out_dev[1024];
|
||||
int audio_out_fd;
|
||||
int audio_out_fdR; //right channel audio for OSS hack
|
||||
@@ -231,6 +271,7 @@ typedef struct
|
||||
FILE *symbol_out_f;
|
||||
float audio_gain;
|
||||
float audio_gainR;
|
||||
float audio_gainA;
|
||||
int audio_out;
|
||||
int dmr_stereo_wav;
|
||||
char wav_out_dir[512];
|
||||
@@ -270,6 +311,10 @@ typedef struct
|
||||
int ssize;
|
||||
int msize;
|
||||
int playfiles;
|
||||
int m17encoder;
|
||||
int m17encoderbrt;
|
||||
int m17encoderpkt;
|
||||
int m17decoderip;
|
||||
int delay;
|
||||
int use_cosine_filter;
|
||||
int unmute_encrypted_p25;
|
||||
@@ -282,6 +327,7 @@ typedef struct
|
||||
int rtl_started;
|
||||
long int rtl_rms;
|
||||
int monitor_input_audio;
|
||||
int analog_only;
|
||||
int pulse_raw_rate_in;
|
||||
int pulse_raw_rate_out;
|
||||
int pulse_digi_rate_in;
|
||||
@@ -296,6 +342,8 @@ typedef struct
|
||||
pa_simple *pulse_digi_dev_in;
|
||||
pa_simple *pulse_digi_dev_out;
|
||||
pa_simple *pulse_digi_dev_outR;
|
||||
char pa_input_idx[100];
|
||||
char pa_output_idx[100];
|
||||
int use_ncurses_terminal;
|
||||
int ncurses_compact;
|
||||
int ncurses_history;
|
||||
@@ -332,10 +380,17 @@ typedef struct
|
||||
char rigctlhostname[1024];
|
||||
|
||||
//UDP Socket Blaster Audio
|
||||
int udp_sockfd;
|
||||
int udp_sockfd; //digital
|
||||
int udp_sockfdA; //analog 48k1
|
||||
int udp_portno;
|
||||
char udp_hostname[1024];
|
||||
|
||||
//M17 UDP for IP frame output
|
||||
int m17_use_ip; //if enabled, open UDP and broadcast IP frame
|
||||
int m17_portno; //default is 17000
|
||||
int m17_udp_sock; //actual UDP socket for M17 to send to
|
||||
char m17_hostname[1024];
|
||||
|
||||
//tcp socket for SDR++, etc
|
||||
int tcp_sockfd;
|
||||
int tcp_portno;
|
||||
@@ -357,7 +412,7 @@ typedef struct
|
||||
char group_in_file[1024];
|
||||
char lcn_in_file[1024];
|
||||
char chan_in_file[1024];
|
||||
char key_in_file[1024];
|
||||
char key_in_file[1024];
|
||||
//end import filenames
|
||||
|
||||
//reverse mute
|
||||
@@ -395,6 +450,12 @@ typedef struct
|
||||
int slot1_on;
|
||||
int slot2_on;
|
||||
|
||||
//enable filter options
|
||||
int use_lpf;
|
||||
int use_hpf;
|
||||
int use_pbf;
|
||||
int use_hpf_d;
|
||||
|
||||
//'DSP' Format Output
|
||||
uint8_t use_dsp_output;
|
||||
char dsp_out_file[2048];
|
||||
@@ -437,14 +498,14 @@ 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[18][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
|
||||
short s_lu[160*6]; //single sample left
|
||||
short s_ru[160*6]; //single sample right
|
||||
short s_l4u[4][160*6]; //quad sample for up to a P25p2 4V
|
||||
short s_r4u[4][160*6]; //quad sample for up to a P25p2 4V
|
||||
//end
|
||||
//end
|
||||
int audio_out_idx;
|
||||
int audio_out_idx2;
|
||||
int audio_out_idxR;
|
||||
@@ -497,6 +558,7 @@ typedef struct
|
||||
char slot0light[8];
|
||||
float aout_gain;
|
||||
float aout_gainR;
|
||||
float aout_gainA;
|
||||
float aout_max_buf[200];
|
||||
float aout_max_bufR[200];
|
||||
float *aout_max_buf_p;
|
||||
@@ -539,6 +601,7 @@ typedef struct
|
||||
unsigned int debug_audio_errorsR;
|
||||
unsigned int debug_header_errors;
|
||||
unsigned int debug_header_critical_errors;
|
||||
int debug_mode; //debug misc things
|
||||
|
||||
// Last dibit read
|
||||
int last_dibit;
|
||||
@@ -606,7 +669,7 @@ typedef struct
|
||||
|
||||
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
|
||||
int dmr_cach_counter; //counter for dmr_cach_fragments 0-3; not sure if needed yet.
|
||||
|
||||
|
||||
//dmr talker alias new/fixed stuff
|
||||
uint8_t dmr_alias_format[2]; //per slot
|
||||
uint8_t dmr_alias_len[2]; //per slot
|
||||
@@ -620,13 +683,22 @@ typedef struct
|
||||
|
||||
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
||||
|
||||
//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_target_id[20];
|
||||
|
||||
int dpmr_color_code;
|
||||
|
||||
short int dmr_stereo; //need state variable for upsample function
|
||||
short int dmr_ms_rc;
|
||||
short int dmr_ms_mode;
|
||||
unsigned int dmrburstL;
|
||||
unsigned int dmrburstR;
|
||||
@@ -654,6 +726,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
|
||||
@@ -685,13 +758,34 @@ typedef struct
|
||||
|
||||
//edacs
|
||||
int ea_mode;
|
||||
int esk_mode;
|
||||
|
||||
unsigned short esk_mask;
|
||||
unsigned long long int edacs_site_id;
|
||||
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_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_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
|
||||
long int trunk_lcn_freq[26]; //max number on an EDACS system, should be enough on DMR too hopefully
|
||||
@@ -703,6 +797,7 @@ typedef struct
|
||||
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_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
|
||||
|
||||
//new nxdn stuff
|
||||
@@ -731,7 +826,7 @@ typedef struct
|
||||
int keyloader; //let us know the keyloader is active
|
||||
|
||||
//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+)
|
||||
char dmr_branding[20];
|
||||
@@ -740,8 +835,8 @@ typedef struct
|
||||
//Remus DMR End Call Alert Beep
|
||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||
|
||||
//Upsampled Audio Smoothing
|
||||
uint8_t audio_smoothing;
|
||||
//Bitmap Filtering Options
|
||||
int audio_smoothing;
|
||||
|
||||
//YSF Fusion Call Strings and Info
|
||||
uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc.
|
||||
@@ -767,11 +862,16 @@ typedef struct
|
||||
|
||||
//M17 Storage
|
||||
uint8_t m17_lsf[360];
|
||||
uint8_t m17_pkt[850];
|
||||
uint8_t m17_pbc_ct; //pbc packet counter
|
||||
uint8_t m17_str_dt; //stream contents
|
||||
|
||||
unsigned long long int m17_dst;
|
||||
unsigned long long int m17_src;
|
||||
uint8_t m17_can;
|
||||
uint8_t m17_can; //can value that was decoded from signal
|
||||
int m17_can_en; //can value supplied to the encoding side
|
||||
int m17_rate; //sampling rate for audio input
|
||||
int m17_vox; //vox enabled via RMS value
|
||||
|
||||
char m17_dst_csd[20];
|
||||
char m17_src_csd[20];
|
||||
@@ -782,10 +882,15 @@ typedef struct
|
||||
uint8_t m17_meta[16]; //packed meta
|
||||
uint8_t m17_enc; //enc type
|
||||
uint8_t m17_enc_st; //scrambler or data subtye
|
||||
int m17encoder_tx; //if TX (encode + decode) M17 Stream is enabled
|
||||
int m17encoder_eot; //signal if we need to send the EOT frame
|
||||
|
||||
//misc str storage
|
||||
char str50a[50];
|
||||
char str50b[50];
|
||||
char str50c[50];
|
||||
char m17dat[50]; //user supplied m17 data input string
|
||||
char m17sms[800]; //user supplied sms text string
|
||||
|
||||
//Codec2
|
||||
#ifdef USE_CODEC2
|
||||
@@ -799,7 +904,7 @@ typedef struct
|
||||
* 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_STR "33331131"
|
||||
//alternating with last symbol opposite of first symbol of LSF
|
||||
@@ -807,8 +912,8 @@ typedef struct
|
||||
#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 M17_BRT "31331111"
|
||||
#define M17_PKT "13113333"
|
||||
|
||||
#define FUSION_SYNC "31111311313113131131"
|
||||
#define INV_FUSION_SYNC "13333133131331313313"
|
||||
@@ -850,7 +955,7 @@ typedef struct
|
||||
#define NXDN_PANDFSW "3131133313131331131" //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_VOICE_SYNC "113111131333131311133333"
|
||||
@@ -922,15 +1027,29 @@ void playSynthesizedVoiceFS3 (dsd_opts * opts, dsd_state * state); //float stere
|
||||
void playSynthesizedVoiceFS4 (dsd_opts * opts, dsd_state * state); //float stereo mix 4v2 P25p2
|
||||
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 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
|
||||
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 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);
|
||||
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();
|
||||
|
||||
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 digitize (dsd_opts* opts, dsd_state* state, int symbol);
|
||||
@@ -1003,7 +1122,13 @@ 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 processYSF(dsd_opts * opts, dsd_state * state); //YSF
|
||||
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
|
||||
void processM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT)
|
||||
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
|
||||
void processM17IPF(dsd_opts * opts, dsd_state * state); //M17 (IPF)
|
||||
void encodeM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR) encoder
|
||||
void encodeM17BRT(dsd_opts * opts, dsd_state * state); //M17 (BRT) encoder
|
||||
void encodeM17PKT(dsd_opts * opts, dsd_state * state); //M17 (PKT) encoder
|
||||
void decodeM17PKT(dsd_opts * opts, dsd_state * state, uint8_t * input, int len); //M17 (PKT) decoder
|
||||
void processP2(dsd_opts * opts, dsd_state * state); //P2
|
||||
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)
|
||||
@@ -1012,7 +1137,16 @@ short nxdn_filter(short sample);
|
||||
short dpmr_filter(short sample);
|
||||
short m17_filter(short sample);
|
||||
|
||||
//utility functions
|
||||
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 ncursesPrinter (dsd_opts * opts, dsd_state * state);
|
||||
@@ -1050,6 +1184,14 @@ void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
|
||||
void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsigned int nBits);
|
||||
void CNXDNConvolution_init();
|
||||
|
||||
//libM17 viterbi decoder
|
||||
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
|
||||
void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state);
|
||||
void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
@@ -1135,8 +1277,14 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
|
||||
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_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[]);
|
||||
char * getTimeL(void);
|
||||
char * getDateL(void);
|
||||
|
||||
//Time and Date Functions
|
||||
char * getTime();
|
||||
char * getTimeC();
|
||||
char * getTimeN(time_t t);
|
||||
char * getDate();
|
||||
char * getDateH();
|
||||
char * getDateN(time_t t);
|
||||
|
||||
//dmr alg stuff
|
||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
||||
@@ -1155,7 +1303,7 @@ bool crc8_ok(uint8_t bits[], unsigned int len);
|
||||
//modified CRC functions for SB/RC
|
||||
uint8_t crc7(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc3(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc4(uint8_t bits[], unsigned int len);
|
||||
uint8_t crc4(uint8_t bits[], unsigned int len);
|
||||
|
||||
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSR(dsd_state * state);
|
||||
@@ -1249,6 +1397,31 @@ 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
|
||||
|
||||
//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
|
||||
int csvGroupImport(dsd_opts * opts, dsd_state * state);
|
||||
int csvLCNImport(dsd_opts * opts, dsd_state * state);
|
||||
@@ -1258,7 +1431,12 @@ int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
|
||||
|
||||
//UDP Socket Connect and UDP Socket Blaster (audio output)
|
||||
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);
|
||||
int m17_socket_receiver(dsd_opts * opts, void * data);
|
||||
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state);
|
||||
int m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
46
package.nix
Normal file
46
package.nix
Normal file
@@ -0,0 +1,46 @@
|
||||
{ lib
|
||||
, stdenv
|
||||
, cmake
|
||||
, mbelib
|
||||
, libsndfile
|
||||
, ncurses
|
||||
, pulseaudio
|
||||
, rtl-sdr
|
||||
, itpp
|
||||
, codec2
|
||||
, portaudioSupport ? true
|
||||
, portaudio ? null
|
||||
}:
|
||||
|
||||
assert portaudioSupport -> portaudio != null;
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "dsd-fme";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = [ cmake ];
|
||||
buildInputs = [
|
||||
mbelib
|
||||
libsndfile
|
||||
itpp
|
||||
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/szechyjs/dsd";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.unix;
|
||||
};
|
||||
}
|
||||
51
patch/DMR_MONO_MODE_20240201.patch
Normal file
51
patch/DMR_MONO_MODE_20240201.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
diff --git a/src/dmr_pi.c b/src/dmr_pi.c
|
||||
index 55dfb83..33fb3ba 100644
|
||||
--- a/src/dmr_pi.c
|
||||
+++ b/src/dmr_pi.c
|
||||
@@ -14,6 +14,9 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
{
|
||||
UNUSED2(opts, CRCCorrect);
|
||||
|
||||
+ //force slot to 0 if using dmr mono handling
|
||||
+ if (opts->dmr_mono == 1) state->currentslot = 0;
|
||||
+
|
||||
if((IrrecoverableErrors == 0))
|
||||
{
|
||||
|
||||
diff --git a/src/dsd_frame.c b/src/dsd_frame.c
|
||||
index 3b2a3e1..ba32618 100644
|
||||
--- a/src/dsd_frame.c
|
||||
+++ b/src/dsd_frame.c
|
||||
@@ -160,7 +160,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
- if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||
+ // if (opts->p25_trunk == 0) //line disabled to allow mono mode while trunking
|
||||
+ dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||
{
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 7be5912..8db6dc3 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -2302,13 +2302,13 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0; //
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
- opts.dmr_mono = 0;
|
||||
- opts.dmr_stereo = 1;
|
||||
+ opts.dmr_mono = 1;
|
||||
+ opts.dmr_stereo = 0; //not sure if this will break anything
|
||||
state.dmr_stereo = 0; //0
|
||||
// opts.setmod_bw = 7000;
|
||||
- sprintf (opts.output_name, "DMR Stereo");
|
||||
- fprintf (stderr,"-fr / DMR Mono switch has been deprecated.\n");
|
||||
- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
+ sprintf (opts.output_name, "DMR Mono");
|
||||
+ // fprintf (stderr,"-fr / DMR Mono switch enabled. \n NOTE: Some ENC options in Slot 2 may not work properly.\n");
|
||||
+ fprintf (stderr,"\n Decoding DMR Stereo BS/MS Simplex in Mono Single Slot Only Configuration.\n");
|
||||
|
||||
}
|
||||
else if (optarg[0] == 'm')
|
||||
152
patch/MTL_MONO_MODE_20240328.patch
Normal file
152
patch/MTL_MONO_MODE_20240328.patch
Normal file
@@ -0,0 +1,152 @@
|
||||
diff --git a/src/dmr_pi.c b/src/dmr_pi.c
|
||||
index 7542c61..d1c8e39 100644
|
||||
--- a/src/dmr_pi.c
|
||||
+++ b/src/dmr_pi.c
|
||||
@@ -14,6 +14,9 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
{
|
||||
UNUSED2(opts, CRCCorrect);
|
||||
|
||||
+ //force slot to 0 if using dmr mono handling
|
||||
+ if (opts->dmr_mono == 1) state->currentslot = 0;
|
||||
+
|
||||
if((IrrecoverableErrors == 0))
|
||||
{
|
||||
|
||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
||||
index 756e468..13316df 100644
|
||||
--- a/src/dsd_audio2.c
|
||||
+++ b/src/dsd_audio2.c
|
||||
@@ -988,6 +988,9 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
memset (stereo_samp2, 0, sizeof(stereo_samp2));
|
||||
memset (stereo_samp3, 0, sizeof(stereo_samp3));
|
||||
|
||||
+ if (opts->dmr_mono == 1)
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4));
|
||||
+
|
||||
//dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
encL = encR = 0;
|
||||
encL = (state->dmr_so >> 6) & 0x1;
|
||||
@@ -1070,8 +1073,16 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//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;
|
||||
+ if (strcmp(modeL, "B") == 0)
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "B") == 0)
|
||||
+ {
|
||||
+ encR = 1;
|
||||
+ encL = 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)
|
||||
diff --git a/src/dsd_frame.c b/src/dsd_frame.c
|
||||
index 577169c..275abb6 100644
|
||||
--- a/src/dsd_frame.c
|
||||
+++ b/src/dsd_frame.c
|
||||
@@ -160,7 +160,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
//we can safely open MBE on any MS or mono handling
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
- if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
|
||||
+ // if (opts->p25_trunk == 0) //line disabled to allow mono mode while trunking
|
||||
+ dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_mono == 1 && state->synctype == 32)
|
||||
{
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 3ca7788..22462a0 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -1645,9 +1645,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
||||
+ fprintf (stderr, "Build Version: AW MTL (20240201) \n");
|
||||
#else
|
||||
- fprintf (stderr, "Build Version: AW %s \n", GIT_TAG);
|
||||
+ fprintf (stderr, "Build Version: AW MTL %s \n", GIT_TAG);
|
||||
#endif
|
||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
||||
|
||||
@@ -2474,14 +2474,18 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 0;
|
||||
- opts.dmr_stereo = 1;
|
||||
- opts.dmr_mono = 0;
|
||||
+ // opts.dmr_stereo = 1;
|
||||
+ // opts.dmr_mono = 0;
|
||||
// opts.setmod_bw = 7000;
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
- sprintf (opts.output_name, "DMR");
|
||||
-
|
||||
- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
+ opts.dmr_mono = 1;
|
||||
+ opts.dmr_stereo = 0; //not sure if this will break anything
|
||||
+ state.dmr_stereo = 0; //0
|
||||
+ // opts.setmod_bw = 7000;
|
||||
+ sprintf (opts.output_name, "DMR Mono");
|
||||
+ // fprintf (stderr,"-fr / DMR Mono switch enabled. \n NOTE: Some ENC options in Slot 2 may not work properly.\n");
|
||||
+ fprintf (stderr,"\n Decoding DMR Stereo BS/MS Simplex in Mono Single Slot Only Configuration.\n");
|
||||
}
|
||||
//change ft to only do P25 and DMR (TDMA trunking modes)
|
||||
else if (optarg[0] == 't')
|
||||
@@ -2558,13 +2562,13 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0; //
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
- opts.dmr_mono = 0;
|
||||
- opts.dmr_stereo = 1;
|
||||
+ opts.dmr_mono = 1;
|
||||
+ opts.dmr_stereo = 0; //not sure if this will break anything
|
||||
state.dmr_stereo = 0; //0
|
||||
// opts.setmod_bw = 7000;
|
||||
- sprintf (opts.output_name, "DMR Stereo");
|
||||
- fprintf (stderr,"-fr / DMR Mono switch has been deprecated.\n");
|
||||
- fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
+ sprintf (opts.output_name, "DMR Mono");
|
||||
+ // fprintf (stderr,"-fr / DMR Mono switch enabled. \n NOTE: Some ENC options in Slot 2 may not work properly.\n");
|
||||
+ fprintf (stderr,"\n Decoding DMR Stereo BS/MS Simplex in Mono Single Slot Only Configuration.\n");
|
||||
|
||||
}
|
||||
else if (optarg[0] == 'm')
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index 73965dc..e5b38aa 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -2297,8 +2297,8 @@ 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 ("------------------------------------------------------------------------------\n");
|
||||
+ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW MTL (20240328)");
|
||||
+ printw ("------------------------------------------------------------------------------\n");
|
||||
}
|
||||
#elif LIMAZULUTWEAKS
|
||||
if (opts->ncurses_compact == 1)
|
||||
@@ -2336,12 +2336,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
#ifdef AERO_BUILD
|
||||
if (i == 5) printw (" %s ", "Aero Build");
|
||||
- if (i == 6) printw (" AW (20231015) \n");
|
||||
+ if (i == 6) printw (" AW MTL (20240328) \n");
|
||||
#elif ZDEV_BUILD
|
||||
- if (i == 5) printw (" %s ", "AW ");
|
||||
+ if (i == 5) printw (" %s ", "AW MTL");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
- #else
|
||||
- if (i == 5) printw (" %s ", "AW ");
|
||||
+ #else
|
||||
+ if (i == 5) printw (" %s ", "AW MTL");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
#endif
|
||||
else printw ("\n");
|
||||
277
patch/cretu_no_dmr_idle.patch
Normal file
277
patch/cretu_no_dmr_idle.patch
Normal file
@@ -0,0 +1,277 @@
|
||||
diff --git a/include/dsd.h b/include/dsd.h
|
||||
index 9ebf3f1..c5ac68a 100644
|
||||
--- a/include/dsd.h
|
||||
+++ b/include/dsd.h
|
||||
@@ -18,16 +18,16 @@
|
||||
*/
|
||||
|
||||
//defined by CMakeLists.txt -- Disable by using cmake -DCOLORS=OFF ..
|
||||
-#ifdef PRETTY_COLORS
|
||||
-#define KNRM "\x1B[0m"
|
||||
-#define KRED "\x1B[31m"
|
||||
-#define KGRN "\x1B[32m"
|
||||
-#define KYEL "\x1B[33m"
|
||||
-#define KBLU "\x1B[34m"
|
||||
-#define KMAG "\x1B[35m"
|
||||
-#define KCYN "\x1B[36m"
|
||||
-#define KWHT "\x1B[37m"
|
||||
-#else
|
||||
+// #ifdef PRETTY_COLORS
|
||||
+// #define KNRM "\x1B[0m"
|
||||
+// #define KRED "\x1B[31m"
|
||||
+// #define KGRN "\x1B[32m"
|
||||
+// #define KYEL "\x1B[33m"
|
||||
+// #define KBLU "\x1B[34m"
|
||||
+// #define KMAG "\x1B[35m"
|
||||
+// #define KCYN "\x1B[36m"
|
||||
+// #define KWHT "\x1B[37m"
|
||||
+// #else
|
||||
#define KNRM ""
|
||||
#define KRED ""
|
||||
#define KGRN ""
|
||||
@@ -36,7 +36,7 @@
|
||||
#define KMAG ""
|
||||
#define KCYN ""
|
||||
#define KWHT ""
|
||||
-#endif
|
||||
+// #endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
diff --git a/src/dmr_bs.c b/src/dmr_bs.c
|
||||
index bdab262..17a9e70 100644
|
||||
--- a/src/dmr_bs.c
|
||||
+++ b/src/dmr_bs.c
|
||||
@@ -266,14 +266,14 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
||||
{
|
||||
|
||||
- fprintf (stderr,"%s ", timestr);
|
||||
+ // fprintf (stderr,"%s ", timestr);
|
||||
if (internalslot == 0)
|
||||
{
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
- fprintf (stderr,"Sync: +DMR ");
|
||||
+ // fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
- else fprintf (stderr,"Sync: -DMR ");
|
||||
+ else {}//fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
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
|
||||
|
||||
@@ -284,9 +284,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
- fprintf (stderr,"Sync: +DMR ");
|
||||
+ // fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
- else fprintf (stderr,"Sync: -DMR ");
|
||||
+ else {}//fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
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
|
||||
|
||||
diff --git a/src/dmr_data.c b/src/dmr_data.c
|
||||
index 87f4dfd..57e5647 100644
|
||||
--- a/src/dmr_data.c
|
||||
+++ b/src/dmr_data.c
|
||||
@@ -232,10 +232,10 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->slot2light, "[sLoT2]");
|
||||
}
|
||||
|
||||
- if (state->dmr_ms_mode == 0)
|
||||
- {
|
||||
- fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
- }
|
||||
+ // if (state->dmr_ms_mode == 0)
|
||||
+ // {
|
||||
+ // fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
+ // }
|
||||
|
||||
// Slot type - Second part - Parity bit
|
||||
for (i = 0; i < 5; i++)
|
||||
@@ -292,6 +292,13 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1
|
||||
info[(2*i) + 99] = (1 & dibit); // bit 0
|
||||
}
|
||||
+
|
||||
+ // if (state->dmr_ms_mode == 0 && burst != 0x09)
|
||||
+ if (burst != 0x09)
|
||||
+ {
|
||||
+ printFrameSync (opts, state, "+DMR ", 90, NULL); //don't think the values matter
|
||||
+ fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
+ }
|
||||
|
||||
//don't run on MS Reverse Channel Data
|
||||
if (state->dmr_ms_rc == 0) dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
||||
@@ -303,15 +310,16 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//ending line break
|
||||
- fprintf(stderr, "\n");
|
||||
+ if (burst != 0x09)
|
||||
+ fprintf(stderr, "\n");
|
||||
|
||||
END:
|
||||
if (SlotTypeOk == 0 || cach_okay != 1)
|
||||
{
|
||||
- fprintf (stderr, "%s", KRED);
|
||||
- fprintf (stderr, "| CACH/Burst FEC ERR");
|
||||
- fprintf (stderr, "%s", KNRM);
|
||||
- fprintf (stderr, "\n");
|
||||
+ // fprintf (stderr, "%s", KRED);
|
||||
+ // fprintf (stderr, "| CACH/Burst FEC ERR");
|
||||
+ // fprintf (stderr, "%s", KNRM);
|
||||
+ // fprintf (stderr, "\n");
|
||||
dmr_reset_blocks (opts, state); //failsafe to reset all data header and blocks when bad tact or slottype
|
||||
}
|
||||
|
||||
diff --git a/src/dmr_dburst.c b/src/dmr_dburst.c
|
||||
index fe81158..078524d 100644
|
||||
--- a/src/dmr_dburst.c
|
||||
+++ b/src/dmr_dburst.c
|
||||
@@ -205,7 +205,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
//flag off prop head when not looking at data blocks
|
||||
if (databurst != 0x6 && databurst != 0x7 && databurst != 0x8 && databurst != 0xA && databurst != 0xB) state->data_p_head[slot] = 0;
|
||||
|
||||
- if (databurst != 0xEB)
|
||||
+ if (databurst != 0xEB && databurst != 0x09)
|
||||
{
|
||||
if (state->dmr_ms_mode == 0)
|
||||
{
|
||||
diff --git a/src/dmr_flco.c b/src/dmr_flco.c
|
||||
index 839b085..e43b568 100644
|
||||
--- a/src/dmr_flco.c
|
||||
+++ b/src/dmr_flco.c
|
||||
@@ -790,21 +790,23 @@ uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
|
||||
crc = crc8_ok(slco_bits, 36);
|
||||
|
||||
//only run SLCO on good everything
|
||||
- if (h1 && h2 && h3 && crc) dmr_slco (opts, state, slco_bits);
|
||||
- else
|
||||
- {
|
||||
- //this line break issue is wracking on my OCD for clean line breaks
|
||||
- if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) ; //no line break if current slot is voice with payload enabled
|
||||
- else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) ; //no line break if current slot is voice with payload enabled
|
||||
- else fprintf (stderr, "\n");
|
||||
- fprintf (stderr, "%s", KRED);
|
||||
- fprintf (stderr, " SLCO CRC ERR");
|
||||
- fprintf (stderr, "%s", KNRM);
|
||||
- if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) //if current slot is voice with payload enabled
|
||||
- fprintf (stderr, "\n");
|
||||
- else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) //if current slot is voice with payload enabled
|
||||
- fprintf (stderr, "\n");
|
||||
- }
|
||||
+ if (h1 && h2 && h3 && crc) {} //dmr_slco (opts, state, slco_bits);
|
||||
+ // else
|
||||
+ // {
|
||||
+ // //this line break issue is wracking on my OCD for clean line breaks
|
||||
+ // if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) {} //no line break if current slot is voice with payload enabled
|
||||
+ // else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) {} //no line break if current slot is voice with payload enabled
|
||||
+ // else {} //fprintf (stderr, "\n");
|
||||
+ // // fprintf (stderr, "%s", KRED);
|
||||
+ // // fprintf (stderr, " SLCO CRC ERR");
|
||||
+ // // fprintf (stderr, "%s", KNRM);
|
||||
+ // if (opts->payload == 1 && state->dmrburstL == 16 && state->currentslot == 0) //if current slot is voice with payload enabled
|
||||
+ // fprintf (stderr, "\n");
|
||||
+ // else if (opts->payload == 1 && state->dmrburstR == 16 && state->currentslot == 1) //if current slot is voice with payload enabled
|
||||
+ // fprintf (stderr, "\n");
|
||||
+ // }
|
||||
+
|
||||
+ UNUSED(opts);
|
||||
|
||||
}
|
||||
return (err); //return err value based on success or failure, even if we aren't checking it
|
||||
@@ -935,8 +937,11 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
uint8_t xpt_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //priority TG hash
|
||||
|
||||
//initial line break
|
||||
- fprintf (stderr, "\n");
|
||||
- fprintf (stderr, "%s", KYEL);
|
||||
+ if (slco != 0)
|
||||
+ {
|
||||
+ fprintf (stderr, "\n");
|
||||
+ fprintf (stderr, "%s", KYEL);
|
||||
+ }
|
||||
|
||||
if (slco == 0x2) //C_SYS_Parms
|
||||
{
|
||||
@@ -973,7 +978,8 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
else sprintf (state->dmr_site_parms, "TIII %s:%d-%d;%04X; ", model_str, net, site, syscode);
|
||||
}
|
||||
else if (slco == 0x0) //null
|
||||
- fprintf (stderr, " SLCO NULL ");
|
||||
+ // fprintf (stderr, " SLCO NULL ");
|
||||
+ {}
|
||||
else if (slco == 0x1)
|
||||
{
|
||||
fprintf (stderr, " Activity Update"); //102 361-2 7.1.3.2
|
||||
diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c
|
||||
index 062bb20..f47a447 100644
|
||||
--- a/src/dsd_frame_sync.c
|
||||
+++ b/src/dsd_frame_sync.c
|
||||
@@ -940,7 +940,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
- printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
+ // printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 10;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
@@ -1068,7 +1068,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1) //&& opts->dmr_stereo == 0
|
||||
{
|
||||
- printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
+ // printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 13;
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
@@ -1443,7 +1443,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1))
|
||||
{
|
||||
- fprintf (stderr,"Sync: no sync\n");
|
||||
+ // fprintf (stderr,"Sync: no sync\n");
|
||||
// fprintf (stderr,"Press CTRL + C to close.\n");
|
||||
|
||||
}
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 98f2ead..b09cb81 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -1687,7 +1687,7 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
||||
+ fprintf (stderr, "Build Version: AW (20240523) \n");
|
||||
#else
|
||||
fprintf (stderr, "Build Version: AW %s \n", GIT_TAG);
|
||||
#endif
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index a5442af..514b9ae 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -2423,7 +2423,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 (20240523)");
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
}
|
||||
#elif LIMAZULUTWEAKS
|
||||
@@ -2462,8 +2462,8 @@ 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 ", "Cretu Build");
|
||||
+ if (i == 6) printw (" AW (20240523) \n");
|
||||
#elif ZDEV_BUILD
|
||||
if (i == 5) printw (" %s ", "AW ");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
@@ -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", "");
|
||||
@@ -0,0 +1,499 @@
|
||||
diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c
|
||||
index 6ee44d6..45502a4 100644
|
||||
--- a/src/dmr_csbk.c
|
||||
+++ b/src/dmr_csbk.c
|
||||
@@ -520,6 +520,26 @@ 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
|
||||
@@ -554,6 +574,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 839b085..637debf 100644
|
||||
--- a/src/dmr_flco.c
|
||||
+++ b/src/dmr_flco.c
|
||||
@@ -298,20 +298,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
if (type != 2) //VLC and EMB, set our target, source, so, and fid per channel
|
||||
{
|
||||
- if (state->currentslot == 0)
|
||||
- {
|
||||
- state->dmr_fid = fid;
|
||||
- state->dmr_so = so;
|
||||
- state->lasttg = target;
|
||||
- state->lastsrc = source;
|
||||
- }
|
||||
- if (state->currentslot == 1)
|
||||
- {
|
||||
- state->dmr_fidR = fid;
|
||||
- state->dmr_soR = so;
|
||||
- state->lasttgR = target;
|
||||
- state->lastsrcR = source;
|
||||
- }
|
||||
+ //moved per call further down past the call_string stuff
|
||||
|
||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||
if (opts->p25_is_tuned == 1)
|
||||
@@ -337,6 +324,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 +343,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;
|
||||
+ }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -612,6 +611,69 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
fprintf (stderr, "Key %010llX ", state->RR);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
+
|
||||
+ if (type != 2)
|
||||
+ {
|
||||
+ if (state->currentslot == 0)
|
||||
+ {
|
||||
+ state->dmr_fid = fid;
|
||||
+ state->dmr_so = so;
|
||||
+ state->lasttg = target;
|
||||
+ state->lastsrc = source;
|
||||
+ char * timestr = NULL;
|
||||
+ char * datestr = NULL;
|
||||
+ timestr = getTime();
|
||||
+ datestr = getDate();
|
||||
+
|
||||
+ //setup a call string for the per call (group/private and/or emergency)
|
||||
+ char cs[200]; memset (cs, 0, 200*sizeof(char));
|
||||
+ int x = 0;
|
||||
+ for (int i = 0; i < 200; i++)
|
||||
+ {
|
||||
+ //copy over non space and non termination values from call string
|
||||
+ if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
|
||||
+ cs[x++] = state->call_string[0][i];
|
||||
+ }
|
||||
+ cs[x] = 0; //terminate
|
||||
+
|
||||
+ //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 - %s - TG %d - RD %d", opts->wav_out_dir, datestr, timestr, state->dmr_color_code, cs, target, source);
|
||||
+ openWavOutFileL (opts, state);
|
||||
+ }
|
||||
+ free (timestr); free(datestr);
|
||||
+ }
|
||||
+ if (state->currentslot == 1)
|
||||
+ {
|
||||
+ state->dmr_fidR = fid;
|
||||
+ state->dmr_soR = so;
|
||||
+ state->lasttgR = target;
|
||||
+ state->lastsrcR = source;
|
||||
+ char * timestr = NULL;
|
||||
+ char * datestr = NULL;
|
||||
+ timestr = getTime();
|
||||
+ datestr = getDate();
|
||||
+
|
||||
+ //setup a call string for the per call (group/private and/or emergency)
|
||||
+ char cs[200]; memset (cs, 0, 200*sizeof(char));
|
||||
+ int x = 0;
|
||||
+ for (int i = 0; i < 200; i++)
|
||||
+ {
|
||||
+ //copy over non space and non termination values from call string
|
||||
+ if (i != 0 && state->call_string[1][i] != ' ' && state->call_string[1][i] != 0)
|
||||
+ cs[x++] = state->call_string[1][i];
|
||||
+ }
|
||||
+ cs[x] = 0; //terminate
|
||||
+
|
||||
+ //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 - %s - TG %d - RD %d", opts->wav_out_dir, datestr, timestr, state->dmr_color_code, cs, target, source);
|
||||
+ openWavOutFileR (opts, state);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/dsd_file.c b/src/dsd_file.c
|
||||
index 6f4ecaa..f4b201d 100644
|
||||
--- a/src/dsd_file.c
|
||||
+++ b/src/dsd_file.c
|
||||
@@ -555,6 +555,16 @@ void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_f);
|
||||
+ char newfilename[1032];
|
||||
+ int result; UNUSED(result);
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
||||
+ result = rename (opts->wav_out_file, newfilename);
|
||||
+ // fprintf (stderr, "\n Close WAV FileF %s; Result: %d \n", newfilename, result);
|
||||
+
|
||||
+ //copy back to wav_out_file string for ncurses display
|
||||
+ memcpy (opts->wav_out_file, newfilename, 1023);
|
||||
+ opts->wav_out_file[1023] = 0;
|
||||
+
|
||||
}
|
||||
|
||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
@@ -562,6 +572,16 @@ void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_f);
|
||||
+ char newfilename[1032];
|
||||
+ int result; UNUSED(result);
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
||||
+ result = rename (opts->wav_out_file, newfilename);
|
||||
+ // fprintf (stderr, "\n Close WAV FileL %s; Result: %d \n", newfilename, result);
|
||||
+
|
||||
+ //copy back to wav_out_file string for ncurses display
|
||||
+ memcpy (opts->wav_out_file, newfilename, 1023);
|
||||
+ opts->wav_out_file[1023] = 0;
|
||||
+
|
||||
}
|
||||
|
||||
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
@@ -569,6 +589,15 @@ void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_fR);
|
||||
+ char newfilename[1032];
|
||||
+ int result; UNUSED(result);
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_fileR);
|
||||
+ result = rename (opts->wav_out_fileR, newfilename);
|
||||
+ // fprintf (stderr, "\n Close WAV FileR %s; Result: %d \n", newfilename, result);
|
||||
+
|
||||
+ //copy back to wav_out_file string for ncurses display
|
||||
+ memcpy (opts->wav_out_fileR, newfilename, 1023);
|
||||
+ opts->wav_out_fileR[1023] = 0;
|
||||
}
|
||||
|
||||
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 3fb0893..a6d45e5 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -107,6 +107,32 @@ 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
|
||||
+
|
||||
+ //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 //NOTE: Blame seems to be synctest8 not being initialized (will continue to test)
|
||||
// //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
|
||||
@@ -1692,9 +1718,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
||||
+ fprintf (stderr, "Build Version: AW (20240601) 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 fe71539..2702b5d 100644
|
||||
--- a/src/dsd_mbe.c
|
||||
+++ b/src/dsd_mbe.c
|
||||
@@ -1197,7 +1197,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1207,7 +1208,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 a5442af..0cd538d 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -1071,7 +1071,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);
|
||||
@@ -2153,7 +2153,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
char cs[200]; memcpy (cs, state->call_string[0], 200*sizeof(char));
|
||||
|
||||
//close old first, assign name based on time and radio, open wav file
|
||||
- closeWavOutFileL (opts, state);
|
||||
+ if (opts->wav_out_f != NULL)
|
||||
+ closeWavOutFileL (opts, state);
|
||||
|
||||
// sprintf (opts->wav_out_file, "%s/%s %s NXDN - RAN %d - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, rn, tgn, src); //original
|
||||
sprintf (opts->wav_out_file, "%s/%s %s NXDN - RAN %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, rn, cs, tgn, src); //with call string
|
||||
@@ -2198,27 +2199,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)
|
||||
- {
|
||||
- //setup a call string for the per call (group/private and/or emergency)
|
||||
- char cs[200]; memset (cs, 0, 200*sizeof(char));
|
||||
- int x = 0;
|
||||
- for (int i = 0; i < 200; i++)
|
||||
- {
|
||||
- //copy over non space and non termination values from call string
|
||||
- if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
|
||||
- cs[x++] = state->call_string[0][i];
|
||||
- }
|
||||
- cs[x] = 0; //terminate
|
||||
-
|
||||
- //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, datestr, timestr, dcc, tg, rd); //original
|
||||
- sprintf (opts->wav_out_file, "%s/%s %s MS - CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tg, rd); //with cs call string
|
||||
-
|
||||
- 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)
|
||||
{
|
||||
@@ -2233,7 +2221,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++)
|
||||
@@ -2254,27 +2242,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)
|
||||
- {
|
||||
- //setup a call string for the per call (group/private and/or emergency)
|
||||
- char cs[200]; memset (cs, 0, 200*sizeof(char));
|
||||
- int x = 0;
|
||||
- for (int i = 0; i < 200; i++)
|
||||
- {
|
||||
- //copy over non space and non termination values from call string
|
||||
- if (i != 0 && state->call_string[0][i] != ' ' && state->call_string[0][i] != 0)
|
||||
- cs[x++] = state->call_string[0][i];
|
||||
- }
|
||||
- cs[x] = 0; //terminate
|
||||
-
|
||||
- //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, datestr, timestr, dcc, tg, rd); //original
|
||||
- sprintf (opts->wav_out_file, "%s/%s %s CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tg, rd); //with call string
|
||||
-
|
||||
- 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)
|
||||
{
|
||||
@@ -2310,34 +2285,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)
|
||||
- {
|
||||
- //setup a call string for the per call (group/private and/or emergency)
|
||||
- char cs[200]; memset (cs, 0, 200*sizeof(char));
|
||||
- int x = 0;
|
||||
- for (int i = 0; i < 200; i++)
|
||||
- {
|
||||
- //copy over non space and non termination values from call string
|
||||
- if (i != 0 && state->call_string[1][i] != ' ' && state->call_string[1][i] != 0)
|
||||
- cs[x++] = state->call_string[1][i];
|
||||
- }
|
||||
- cs[x] = 0; //terminate
|
||||
-
|
||||
- //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, datestr, timestr, dcc, tgR, rdR); //original
|
||||
- sprintf (opts->wav_out_fileR, "%s/%s %s CC %d - %s - DST %d - SRC %d.wav", opts->wav_out_dir, datestr, timestr, dcc, cs, tgR, rdR); //with call string
|
||||
-
|
||||
- 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", "");
|
||||
@@ -2423,8 +2385,8 @@ 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 ("------------------------------------------------------------------------------\n");
|
||||
+ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20240601)");
|
||||
+ printw ("------------------------------------------------------------------------------\n");
|
||||
}
|
||||
#elif LIMAZULUTWEAKS
|
||||
if (opts->ncurses_compact == 1)
|
||||
@@ -2462,13 +2424,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 (20240601) \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 ");
|
||||
+ #else
|
||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
#endif
|
||||
else printw ("\n");
|
||||
@@ -4426,7 +4388,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
|
||||
{
|
||||
|
||||
509
src/3.c
509
src/3.c
@@ -2,7 +2,7 @@
|
||||
* 3.c
|
||||
* Placeholder File 3 -- This file is for temporary code storage
|
||||
*
|
||||
* A 1/2 Rate Convolutional Decoder for NXDN/M17/YSF
|
||||
* Multiple 1/2 Rate Convolutional Decoders for NXDN/M17/YSF
|
||||
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
@@ -85,3 +85,510 @@ void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
||||
* 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;
|
||||
}
|
||||
@@ -798,26 +798,55 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
|
||||
//debug print
|
||||
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
|
||||
|
||||
if (state->data_header_format[slot] == 13 || state->data_header_format[slot] == 14 || state->data_header_sap[slot] == 10)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n Short Data: ASCII \n" );
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
if (state->dmr_pdu_sf[slot][i] <= 0x7E && state->dmr_pdu_sf[slot][i] >=0x20)
|
||||
{
|
||||
fprintf (stderr, "%c", state->dmr_pdu_sf[slot][i]);
|
||||
}
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
if (i == 47 || i == 95) fprintf (stderr, "\n ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
// #define DMR_ASCII_TEST
|
||||
#ifdef DMR_ASCII_TEST
|
||||
// if (state->data_header_format[slot] == 13 || state->data_header_format[slot] == 14 || state->data_header_sap[slot] == 10)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n DMR PDU ASCII: \n" );
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
if (state->dmr_pdu_sf[slot][i] <= 0x7E && state->dmr_pdu_sf[slot][i] >=0x20)
|
||||
{
|
||||
fprintf (stderr, "%c", state->dmr_pdu_sf[slot][i]);
|
||||
}
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
if (i == 47 || i == 95) fprintf (stderr, "\n ");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// #define DMR_UTF16_TEST
|
||||
#ifdef DMR_UTF16_TEST
|
||||
//utf-16 text messaging (debug)
|
||||
// if (utf-16)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n DMR PDU UTF16: ");
|
||||
uint16_t ch16 = 0;
|
||||
for (i = 25; i < ((blocks+1)*block_len)-4;) //at least one system seems to put out utf-16 at the offset of 25 from testing
|
||||
{
|
||||
ch16 = (uint16_t)state->dmr_pdu_sf[slot][i+0];
|
||||
ch16 <<= 8;
|
||||
ch16 |= (uint16_t)state->dmr_pdu_sf[slot][i+1];
|
||||
// fprintf (stderr, " %04X; ", ch16); //debug for raw values to check grouping for offset
|
||||
|
||||
if (ch16 >= 0x20) //if not a linebreak or terminal commmands
|
||||
fprintf (stderr, "%lc", ch16);
|
||||
else if (ch16 == 0) //if padding
|
||||
fprintf (stderr, "_");
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//reset data header format storage
|
||||
state->data_header_format[slot] = 7;
|
||||
//flag off data header validity
|
||||
|
||||
253
src/dmr_bs.c
253
src/dmr_bs.c
@@ -13,8 +13,9 @@
|
||||
//processing voice and/or data on both BS slots (channels) simultaneously
|
||||
void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, dibit;
|
||||
char * timestr = NULL;
|
||||
|
||||
int i, dibit;
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
@@ -30,8 +31,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
uint8_t syncdata[48];
|
||||
memset (syncdata, 0, sizeof(syncdata));
|
||||
|
||||
uint8_t emb_pdu[16];
|
||||
memset (emb_pdu, 0, sizeof(emb_pdu));
|
||||
|
||||
uint8_t emb_ok = 0;
|
||||
uint8_t tact_okay = 0;
|
||||
@@ -52,22 +56,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof(dummy_bits));
|
||||
|
||||
//add time to mirror printFrameSync
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
//Init slot lights
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
@@ -75,8 +63,18 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//Init the color code status
|
||||
state->color_code_ok = 0;
|
||||
|
||||
vc1 = 2;
|
||||
vc2 = 2;
|
||||
//if coming from the bootsrap, then the slot will still be assigned the last value
|
||||
//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 skipcount = 0;
|
||||
@@ -101,9 +99,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
|
||||
timestr = getTimeC();
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
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
|
||||
for(i = 0; i < 12; i++)
|
||||
@@ -192,19 +194,19 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
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] = (1 & dibit); // bit 0
|
||||
|
||||
//embedded link control
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E
|
||||
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] = (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] = (1 & dibit); // bit 0
|
||||
@@ -213,8 +215,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
sync[24] = 0;
|
||||
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 0] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
@@ -264,7 +266,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
||||
{
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
if (internalslot == 0)
|
||||
{
|
||||
if (opts->inverted_dmr == 0)
|
||||
@@ -273,7 +275,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
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
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
@@ -286,7 +288,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
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
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
@@ -297,26 +299,103 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
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
|
||||
if ( (strcmp (sync, DMR_BS_DATA_SYNC) != 0) && (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) &&
|
||||
( (internalslot == 0 && vc1 == 6) || (internalslot == 1 && vc2 == 6) ) )
|
||||
{
|
||||
|
||||
//if the QR FEC is good, and the P/PI bit is on for RC
|
||||
if (QR_16_7_6_decode(emb_pdu) && emb_pdu[4])
|
||||
{
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
|
||||
if (opts->inverted_dmr == 0)
|
||||
fprintf (stderr,"Sync: +RC ");
|
||||
else fprintf (stderr,"Sync: -RC ");
|
||||
|
||||
dmr_data_sync (opts, state);
|
||||
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
|
||||
dmr_sbrc (opts, state, emb_pdu[4]);
|
||||
|
||||
if (internalslot == 0)
|
||||
vc1 = 7;
|
||||
else vc2 = 7;
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
//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;
|
||||
|
||||
//disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs
|
||||
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
||||
else if (emb_ok == 1)
|
||||
{
|
||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
power = EmbeddedSignalling[4];
|
||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
cc = ((emb_pdu[0] << 3) + (emb_pdu[1] << 2) + (emb_pdu[2] << 1) + emb_pdu[3]);
|
||||
power = emb_pdu[4];
|
||||
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
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
|
||||
//simplifying things
|
||||
char polarity[3];
|
||||
@@ -340,8 +419,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
||||
if (state->dmr_color_code != 16)
|
||||
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)
|
||||
{
|
||||
@@ -417,33 +497,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
|
||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
// run alg refresh after vc6 ambe processing
|
||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state);
|
||||
|
||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
||||
|
||||
//increment the vc counters
|
||||
if (internalslot == 0) vc1++;
|
||||
if (internalslot == 1) vc2++;
|
||||
|
||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||
if (opts->p25_is_tuned == 1)
|
||||
{
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
//'DSP' output to file -- run before sbrc
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
@@ -461,7 +517,31 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
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);
|
||||
|
||||
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
|
||||
cach_err = 1;
|
||||
@@ -503,6 +583,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
ncursesPrinter(opts, state);
|
||||
}
|
||||
|
||||
//
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
} // while loop
|
||||
|
||||
END:
|
||||
@@ -526,7 +613,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
if (tact_okay != 1 || emb_ok != 1)
|
||||
{
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
||||
@@ -549,6 +636,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
||||
@@ -584,22 +678,9 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
//add time to mirror printFrameSync
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
};
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
char * timestr = getTimeC();
|
||||
|
||||
//payload buffer
|
||||
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
||||
@@ -748,7 +829,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
|
||||
@@ -766,8 +847,9 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code);
|
||||
if (state->dmr_color_code != 16)
|
||||
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);
|
||||
|
||||
@@ -849,7 +931,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
//if we have a tact err, then produce sync pattern/err message
|
||||
if (tact_okay != 1 || sync_okay != 1)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| VOICE CACH/SYNC ERR");
|
||||
@@ -871,5 +953,10 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
dmr_reset_blocks (opts, state);
|
||||
}
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
360
src/dmr_csbk.c
360
src/dmr_csbk.c
@@ -13,7 +13,7 @@
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
#define PCLEAR_TUNE_AWAY //disable if slower return is preferred
|
||||
//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)
|
||||
{
|
||||
@@ -283,11 +283,40 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
{
|
||||
state->lasttg = target;
|
||||
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)
|
||||
{
|
||||
state->lasttgR = target;
|
||||
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
|
||||
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);
|
||||
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
|
||||
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->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)
|
||||
{
|
||||
state->lasttgR = target;
|
||||
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
|
||||
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);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
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
|
||||
}
|
||||
@@ -378,89 +439,160 @@ 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,
|
||||
//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 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 ( ((time(NULL) - state->last_vc_sync_time) > opts->trunk_hangtime) && opts->trunk_tune_data_calls == 0) clear = 1;
|
||||
//if the other slot is IDLE or TLC condition -- May consider disabling this one
|
||||
// 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 (state->currentslot == 0 && state->dmrburstR != 16) clear = 2; //&& opts->trunk_tune_data_calls == 0
|
||||
if (state->currentslot == 1 && state->dmrburstL != 16) clear = 3; //&& opts->trunk_tune_data_calls == 0
|
||||
//if no voice header, pi header, or voice sync in the opposite slot currently
|
||||
if (state->currentslot == 0 && (state->dmrburstR != 16 && state->dmrburstR != 0 && state->dmrburstR != 1)) clear = 2;
|
||||
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 (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
|
||||
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 (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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
//display/le bug fix when p_clear activated
|
||||
// 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
|
||||
}
|
||||
|
||||
fprintf (stderr, " Slot %d Clear; Slot %d Data; Remain on DC;", pslot, oslot);
|
||||
clear = 0; //flag as 0 so we won't tune away until data call is completed
|
||||
}
|
||||
}
|
||||
|
||||
if (clear)
|
||||
{
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 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->payload_mi = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->dmr_so = 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->payload_mi = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->dmr_so = 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)
|
||||
@@ -490,6 +622,21 @@ 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
|
||||
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;
|
||||
}
|
||||
if (!gi && opts->trunk_tune_private_calls == 1)
|
||||
{
|
||||
if (state->currentslot == 0) state->dmrburstL = 1;
|
||||
else state->dmrburstR = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 40) //0x28
|
||||
@@ -1026,6 +1173,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);
|
||||
|
||||
//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
|
||||
|
||||
@@ -1115,6 +1269,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//tg and channel info for trunking purposes
|
||||
uint16_t t_tg[24];
|
||||
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
|
||||
if (block_num > 6)
|
||||
@@ -1127,6 +1282,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
memset (t_tg, 0, sizeof(t_tg));
|
||||
memset (ch, 0, sizeof(ch));
|
||||
memset (pch, 0, sizeof(pch));
|
||||
memset (empty, 0, sizeof(empty));
|
||||
|
||||
//treating FL as a form of LCSS
|
||||
if (fl == 2 || fl == 3) //initial or single block (fl2 or fl3)
|
||||
@@ -1143,6 +1299,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
state->cap_plus_block_num[ts]++;
|
||||
}
|
||||
|
||||
//move assignment until later when evaluating for a p_clear condition
|
||||
if (rest_channel != state->dmr_rest_channel)
|
||||
{
|
||||
state->dmr_rest_channel = rest_channel;
|
||||
@@ -1151,7 +1308,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
|
||||
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
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
@@ -1321,15 +1478,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!
|
||||
if (tg != 0) fprintf (stderr, "%5d; ", tg);
|
||||
else fprintf (stderr, " P||D; ");
|
||||
//flag as available for tuning if data calls enabled
|
||||
if (opts->trunk_tune_data_calls == 1) t_tg[i] = tg; //ch[i] = 1;
|
||||
//flag as available for tuning if private calls enabled
|
||||
if (opts->trunk_tune_private_calls == 1) t_tg[i] = tg; //ch[i] = 1;
|
||||
if (tg != 0) x++;
|
||||
|
||||
//add active channel to display string
|
||||
|
||||
//NOTE: Consider only adding this if user toggled or else
|
||||
//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);
|
||||
strcat (state->active_channel[i+1], cap_active);
|
||||
@@ -1424,6 +1581,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]);
|
||||
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
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 11; //break loop
|
||||
}
|
||||
|
||||
@@ -1459,6 +1617,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
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
|
||||
opts->p25_is_tuned = 1;
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
j = 11; //break loop
|
||||
#endif
|
||||
}
|
||||
@@ -1486,6 +1645,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]));
|
||||
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)
|
||||
} //opcode == 0x3E
|
||||
@@ -1551,14 +1729,20 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
else if (opt == 3)
|
||||
fprintf (stderr, " Connect Plus Private Voice Channel Grant;");
|
||||
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
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
|
||||
//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);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
@@ -1668,7 +1852,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;
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
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;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
@@ -1677,7 +1861,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;
|
||||
|
||||
//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);
|
||||
|
||||
//NOTE: Only set CC Frequency from SLC since it will tell us
|
||||
@@ -1759,25 +1943,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)
|
||||
{
|
||||
//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
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t ttarget = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " Connect Plus Channel Termination;");
|
||||
fprintf (stderr, " Connect Plus Data Call Termination;");
|
||||
fprintf (stderr, " Connect Plus Slot Termination;");
|
||||
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
|
||||
//another octet 9? with an 01 in it a few times, could have been a timeslot bit
|
||||
|
||||
//Run p_clear to decide whether or not to return to the control channel
|
||||
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;
|
||||
sprintf (state->dmr_branding, "%s", "Motorola");
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
|
||||
@@ -293,8 +293,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
//if using con+ trunking and last voice observed more than x seconds ago, snap back to con+ cc
|
||||
//con+ voice channels can have extremely long idle periods without properly tearing down
|
||||
#define CON_TUNEAWAY //disable if any unlock issues noted on the logic
|
||||
|
||||
#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)
|
||||
{
|
||||
//bug fixed that caused hopping from CC to VC; decreased to 2 seconds.
|
||||
time_t waitsec = 2;
|
||||
if (opts->trunk_tune_data_calls == 1)
|
||||
waitsec = 4; //increase time for a data call before hopping
|
||||
if ( (time(NULL) - state->last_vc_sync_time > waitsec) )
|
||||
int clear = 0;
|
||||
//IF both slots currently signalling IDLE
|
||||
if (state->dmrburstL == 9 && state->dmrburstR == 9) clear = 1;
|
||||
if (clear == 1)
|
||||
{
|
||||
if (opts->use_rigctl == 1) //rigctl tuning
|
||||
{
|
||||
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
|
||||
state->last_cc_sync_time = 0;
|
||||
state->last_vc_sync_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -207,7 +207,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
|
||||
|
||||
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);
|
||||
|
||||
//'DSP' output to file
|
||||
|
||||
@@ -354,15 +354,18 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (restchannel != state->dmr_rest_channel && restchannel != -1)
|
||||
//only assign this value here if not trunking
|
||||
// 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;
|
||||
//assign to cc freq
|
||||
if (state->trunk_chan_map[restchannel] != 0)
|
||||
if (restchannel != state->dmr_rest_channel && restchannel != -1)
|
||||
{
|
||||
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];
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 1) fprintf (stderr, "%s \n", KGRN);
|
||||
@@ -384,16 +387,19 @@ 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
|
||||
{
|
||||
sprintf (state->call_string[slot], " Cap+");
|
||||
// sprintf (state->call_string[slot], " Cap+");
|
||||
sprintf (state->call_string[slot], "%s","");
|
||||
fprintf (stderr, "Cap+ ");
|
||||
if (flco == 0x4)
|
||||
{
|
||||
strcat (state->call_string[slot], " Grp");
|
||||
// strcat (state->call_string[slot], " Grp");
|
||||
sprintf (state->call_string[slot], " Group ");
|
||||
fprintf (stderr, "Group ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat (state->call_string[slot], " Pri");
|
||||
// strcat (state->call_string[slot], " Pri");
|
||||
sprintf (state->call_string[slot], " Private ");
|
||||
fprintf (stderr, "Private ");
|
||||
}
|
||||
}
|
||||
@@ -445,18 +451,18 @@ 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 (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;
|
||||
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 (gm, "%s", "DE");
|
||||
sprintf (gm, "%s", "B");
|
||||
sprintf (gn, "%s", "ENC LO");
|
||||
state->group_tally++;
|
||||
}
|
||||
|
||||
//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;
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -986,7 +992,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);
|
||||
|
||||
//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);
|
||||
if (ccfreq != 0) state->p25_cc_freq = ccfreq;
|
||||
@@ -1004,21 +1010,35 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
else if (slco == 0xF)
|
||||
{
|
||||
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
|
||||
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,
|
||||
if (state->dmrburstL == 16 && state->dmrburstR == 16)
|
||||
//debug
|
||||
// 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
|
||||
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
|
||||
if (state->p25_cc_freq != 0)
|
||||
{
|
||||
|
||||
33
src/dmr_le.c
33
src/dmr_le.c
@@ -252,7 +252,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 ^ 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;
|
||||
}
|
||||
else //if (txi == 1) //if TXI -- but TXI systems also carry the non-crc protected ENC identifiers
|
||||
@@ -323,7 +323,7 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
}
|
||||
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)
|
||||
// {
|
||||
@@ -332,7 +332,19 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
|
||||
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
|
||||
@@ -416,21 +428,20 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
|
||||
|
||||
SBRC_END:
|
||||
|
||||
//'DSP' output to file -- only RC, or RC and SB?
|
||||
if (power == 1 && opts->use_dsp_output == 1 && sbrc_hex != 0) //if not NULL
|
||||
//'DSP' output to file -- SB and RC
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is RC designation value
|
||||
int k = 0;
|
||||
for (i = 0; i < 24; i++) //12 bytes, SB or RC
|
||||
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is SB and RC designation value
|
||||
for (i = 0; i < 12; i++) //48 bits (includes CC, PPI, LCSS, and QR)
|
||||
// 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
|
||||
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);
|
||||
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);
|
||||
fprintf (pFile, "%X", sbrc_nib);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
208
src/dmr_ms.c
208
src/dmr_ms.c
@@ -13,6 +13,8 @@
|
||||
void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char * timestr = getTimeC();
|
||||
|
||||
int i, j, dibit;
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
@@ -25,9 +27,12 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
uint8_t EmbeddedSignalling[16];
|
||||
|
||||
uint8_t syncdata[48];
|
||||
memset (syncdata, 0, sizeof(syncdata));
|
||||
|
||||
uint8_t emb_pdu[16];
|
||||
memset (emb_pdu, 0, sizeof(emb_pdu));
|
||||
|
||||
//cach
|
||||
char cachdata[25];
|
||||
@@ -36,8 +41,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t tact_bits[7];
|
||||
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t EmbeddedSignallingOk = 0;
|
||||
UNUSED(EmbeddedSignallingOk);
|
||||
uint8_t emb_ok = 0;
|
||||
UNUSED(emb_ok);
|
||||
|
||||
uint8_t internalslot;
|
||||
uint8_t vc;
|
||||
@@ -52,22 +57,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof (dummy_bits));
|
||||
|
||||
//add time to mirror printFrameSync
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
vc = 2;
|
||||
|
||||
//Hardset variables for MS/Mono
|
||||
@@ -167,10 +156,8 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
|
||||
// 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] = (1 & dibit); // bit 0
|
||||
@@ -178,35 +165,17 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
sync[24] = 0;
|
||||
|
||||
//test for RC sync pattern in MS sourced audio
|
||||
if ( strcmp (sync, DMR_RC_DATA_SYNC) == 0)
|
||||
{
|
||||
state->dmr_ms_rc = 1;
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||
}
|
||||
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];
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 0] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) emb_pdu[i + 8] = syncdata[i + 40];
|
||||
|
||||
EmbeddedSignallingOk = -1;
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling))
|
||||
emb_ok = -1;
|
||||
if(QR_16_7_6_decode(emb_pdu))
|
||||
{
|
||||
EmbeddedSignallingOk = 1;
|
||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
power = EmbeddedSignalling[4];
|
||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
|
||||
emb_ok = 1;
|
||||
cc = ((emb_pdu[0] << 3) + (emb_pdu[1] << 2) + (emb_pdu[2] << 1) + emb_pdu[3]);
|
||||
power = emb_pdu[4];
|
||||
lcss = ((emb_pdu[5] << 1) + emb_pdu[6]);
|
||||
state->dmr_color_code = state->color_code = cc;
|
||||
}
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
@@ -275,38 +244,35 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (state->dmr_ms_rc == 0)
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
//TODO: Consider copying f_l to f_r for left and right channel saturation on MS mode
|
||||
@@ -354,7 +320,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
if (vc > 6) goto END;
|
||||
|
||||
skipDibit (opts, state, 144); //skip to next tdma channel
|
||||
state->dmr_ms_rc = 0;
|
||||
|
||||
//since we are in a loop, run ncursesPrinter here
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
@@ -382,15 +347,22 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
state->dmr_stereo = 0;
|
||||
state->dmr_ms_mode = 0;
|
||||
state->dmr_ms_rc = 0;
|
||||
state->directmode = 0; //flag off
|
||||
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
|
||||
char * timestr = getTimeC();
|
||||
|
||||
int i, dibit;
|
||||
int *dibit_p;
|
||||
|
||||
@@ -414,22 +386,6 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
char cachdata[25];
|
||||
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->currentslot = 0; //force to slot 0
|
||||
|
||||
@@ -565,13 +521,15 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
fprintf (stderr, "%s ", timestr);
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
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, "\n");
|
||||
|
||||
@@ -639,6 +597,11 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//errors due to skipping other slot
|
||||
// cach_err = dmr_cach (opts, state, cachdata);
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
skipDibit (opts, state, 144); //skip to next TDMA slot
|
||||
dmrMS (opts, state); //bootstrap into full TDMA frame
|
||||
@@ -648,27 +611,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
|
||||
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char * timestr = getTimeC();
|
||||
|
||||
int i;
|
||||
int dibit;
|
||||
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
|
||||
dibit_p = state->dmr_payload_p - 90;
|
||||
for (i = 0; i < 90; i++) //90
|
||||
@@ -677,7 +626,6 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < 54; i++)
|
||||
@@ -685,16 +633,17 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
fprintf (stderr, "%s ", timestr);
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
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->slot2light, "%s", "");
|
||||
@@ -710,16 +659,23 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
state->directmode = 0; //flag off
|
||||
|
||||
//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
|
||||
{
|
||||
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
|
||||
for (i = 0; i < 66; i++) //66
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,33 +8,6 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
char * getTimeL(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 * getDateL(void) {
|
||||
char datename[120];
|
||||
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 dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
|
||||
{
|
||||
|
||||
@@ -274,16 +247,29 @@ void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DM
|
||||
FILE * pFile; //file pointer
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
char * timestr = getTime();
|
||||
char * datestr = getDate();
|
||||
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
//write current date/time if not present in LRRP data
|
||||
if (!year) fprintf (pFile, "%s\t", getDateL() ); //current date, only add this IF no included timestamp in LRRP data?
|
||||
if (!year) fprintf (pFile, "%s\t", getTimeL() ); //current timestamp, only add this IF no included timestamp in LRRP data?
|
||||
if (!year) fprintf (pFile, "%s\t", datestr ); //current date, only add this IF no included timestamp in LRRP data?
|
||||
if (!year) fprintf (pFile, "%s\t", timestr ); //current timestamp, only add this IF no included timestamp in LRRP data?
|
||||
if (year) fprintf (pFile, "%04d/%02d/%02d\t%02d:%02d:%02d\t", year, month, day, hour, minute, second); //add timestamp from decoded audio if available
|
||||
//write data header source if not available in lrrp data
|
||||
if (!source) fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header
|
||||
if (source) fprintf (pFile, "%08d\t", source); //add source form decoded audio if available, else its from the header
|
||||
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pot_report)
|
||||
|
||||
@@ -17,6 +17,13 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
|
||||
if((IrrecoverableErrors == 0))
|
||||
{
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->payload_algid = PI_BYTE[0];
|
||||
|
||||
@@ -472,13 +472,17 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//flag back off if key is provided
|
||||
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
|
||||
for(i = start; i < end; i++)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
|
||||
if (opts->floating_point == 0)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
}
|
||||
|
||||
126
src/dsd_audio.c
126
src/dsd_audio.c
@@ -23,6 +23,9 @@ pa_sample_spec zz;
|
||||
pa_sample_spec cc;
|
||||
pa_sample_spec ff; //float
|
||||
|
||||
//pulse audio buffer attributes (input latency)
|
||||
pa_buffer_attr lt;
|
||||
|
||||
void closePulseOutput (dsd_opts * opts)
|
||||
{
|
||||
pa_simple_free (opts->pulse_digi_dev_out);
|
||||
@@ -38,6 +41,12 @@ void closePulseInput (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.channels = opts->pulse_raw_out_channels;
|
||||
ss.rate = opts->pulse_raw_rate_out;
|
||||
@@ -52,28 +61,130 @@ 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
|
||||
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* ss = 0; //NULL and 0 are same in this context
|
||||
|
||||
if (opts->floating_point == 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 (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);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->floating_point == 1)
|
||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &ff, fl, NULL, NULL);
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
char * dev = NULL;
|
||||
if (opts->pa_input_idx[0] != 0)
|
||||
dev = opts->pa_input_idx;
|
||||
|
||||
int err = 0;
|
||||
|
||||
cc.format = PA_SAMPLE_S16NE;
|
||||
cc.channels = opts->pulse_digi_in_channels;
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
void openOSSOutput (dsd_opts * opts)
|
||||
@@ -575,7 +686,7 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
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
|
||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||
@@ -712,6 +823,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)
|
||||
{
|
||||
opts->audio_in_type = 8;
|
||||
|
||||
768
src/dsd_audio2.c
768
src/dsd_audio2.c
@@ -12,6 +12,9 @@
|
||||
#include "dsd.h"
|
||||
#include <math.h>
|
||||
|
||||
//NOTE: Tones produce ringing sound when put through the hpf_d, may want to look into tweaking it,
|
||||
//or looking for a way to store is_tone by glancing at ambe_d values and not running hpf_d on them
|
||||
|
||||
//TODO: WAV File saving (works fine on shorts, but on float, writing short to wav is not auto-gained,
|
||||
//so super quiet, either convert to float wav files, or run processAudio AFTER memcpy of the temp_buf)
|
||||
|
||||
@@ -721,6 +724,128 @@ void playSynthesizedVoiceFM (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//Mono - Short (SB16LE) - Drop-in replacement for playSyntesizedVoice, but easier to manipulate
|
||||
void playSynthesizedVoiceMS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i;
|
||||
size_t len = state->audio_out_idx;
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " L LEN: %d", len);
|
||||
|
||||
short mono_samp[len];
|
||||
memset (mono_samp, 0, len*sizeof(short));
|
||||
|
||||
if (opts->slot1_on == 0)
|
||||
goto MS_END;
|
||||
|
||||
if (len == 160)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
mono_samp[i] = state->s_l[i];
|
||||
}
|
||||
else if (len == 960)
|
||||
{
|
||||
state->audio_out_buf_p -= 960; //rewind first
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
mono_samp[i] = *state->audio_out_buf_p;
|
||||
state->audio_out_buf_p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->use_hpf_d == 1)
|
||||
hpf_dL(state, state->s_l, len);
|
||||
|
||||
if (opts->audio_out_type == 0) //Pulse Audio
|
||||
pa_simple_write(opts->pulse_digi_dev_out, mono_samp, len*2, NULL);
|
||||
|
||||
if (opts->audio_out_type == 8) //UDP Audio
|
||||
udp_socket_blaster (opts, state, len*2, mono_samp);
|
||||
|
||||
if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS
|
||||
write (opts->audio_out_fd, mono_samp, len*2);
|
||||
|
||||
MS_END:
|
||||
|
||||
//run cleanup since we pulled stuff from processAudio
|
||||
state->audio_out_idx = 0;
|
||||
|
||||
//set short temp buffer to baseline
|
||||
memset (state->s_l, 0, sizeof(state->s_l));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Mono - Short (SB16LE) - Drop-in replacement for playSyntesizedVoiceR, but easier to manipulate
|
||||
void playSynthesizedVoiceMSR (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i;
|
||||
size_t len = state->audio_out_idxR;
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, " R LEN: %d", len);
|
||||
|
||||
short mono_samp[len];
|
||||
memset (mono_samp, 0, len*sizeof(short));
|
||||
|
||||
if (opts->slot2_on == 0)
|
||||
goto MS_ENDR;
|
||||
|
||||
if (len == 160)
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
mono_samp[i] = state->s_r[i];
|
||||
}
|
||||
else if (len == 960)
|
||||
{
|
||||
state->audio_out_buf_pR -= 960; //rewind first
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
mono_samp[i] = *state->audio_out_buf_pR;
|
||||
state->audio_out_buf_pR++;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->use_hpf_d == 1)
|
||||
hpf_dR(state, mono_samp, len);
|
||||
|
||||
if (opts->audio_out_type == 0) //Pulse Audio
|
||||
pa_simple_write(opts->pulse_digi_dev_out, mono_samp, len*2, NULL);
|
||||
|
||||
if (opts->audio_out_type == 8) //UDP Audio
|
||||
udp_socket_blaster (opts, state, len*2, mono_samp);
|
||||
|
||||
if (opts->audio_out_type == 1 || opts->audio_out_type == 2 || opts->audio_out_type == 5) //STDOUT or OSS
|
||||
write (opts->audio_out_fd, mono_samp, len*2);
|
||||
|
||||
MS_ENDR:
|
||||
|
||||
//run cleanup since we pulled stuff from processAudioR
|
||||
state->audio_out_idxR = 0;
|
||||
|
||||
//set short temp buffer to baseline
|
||||
memset (state->s_r, 0, sizeof(state->s_r));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Stereo Mix - Short (SB16LE) -- When Playing Short FDMA samples when setup for stereo output
|
||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
@@ -728,7 +853,7 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
|
||||
int i;
|
||||
int encL;
|
||||
short stereo_samp1[320]; //8k 2-channel stereo interleave mix
|
||||
memset (stereo_samp1, 1, sizeof(stereo_samp1));
|
||||
memset (stereo_samp1, 0, sizeof(stereo_samp1));
|
||||
|
||||
//enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
encL = 0;
|
||||
@@ -785,15 +910,19 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
|
||||
//likewise, override and unmute if TG hold matches TG
|
||||
if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
|
||||
//test hpf
|
||||
if (opts->use_hpf_d == 1)
|
||||
hpf_dL(state, state->s_l, 160);
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
if (!encL)
|
||||
stereo_samp1[i*2+0] = state->s_l[i] / 2;
|
||||
stereo_samp1[i*2+0] = state->s_l[i] / 1;
|
||||
|
||||
//testing double left and right channel
|
||||
if (!encL)
|
||||
stereo_samp1[i*2+1] = state->s_l[i] / 2;
|
||||
stereo_samp1[i*2+1] = state->s_l[i] / 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -817,9 +946,9 @@ void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state)
|
||||
state->audio_out_idx = 0;
|
||||
state->audio_out_idxR = 0;
|
||||
|
||||
//set float temp buffer to baseline
|
||||
memset (state->s_l, 1, sizeof(state->s_l));
|
||||
memset (state->s_r, 1, sizeof(state->s_r));
|
||||
//set short temp buffer to baseline
|
||||
memset (state->s_l, 0, sizeof(state->s_l));
|
||||
memset (state->s_r, 0, sizeof(state->s_r));
|
||||
|
||||
if (state->audio_out_idx2 >= 800000)
|
||||
{
|
||||
@@ -855,9 +984,9 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
short stereo_samp2[320]; //8k 2-channel stereo interleave mix
|
||||
short stereo_samp3[320]; //8k 2-channel stereo interleave mix
|
||||
|
||||
memset (stereo_samp1, 1, sizeof(stereo_samp1));
|
||||
memset (stereo_samp2, 1, sizeof(stereo_samp2));
|
||||
memset (stereo_samp3, 1, sizeof(stereo_samp3));
|
||||
memset (stereo_samp1, 0, sizeof(stereo_samp1));
|
||||
memset (stereo_samp2, 0, sizeof(stereo_samp2));
|
||||
memset (stereo_samp3, 0, sizeof(stereo_samp3));
|
||||
|
||||
//dmr enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
encL = encR = 0;
|
||||
@@ -906,8 +1035,8 @@ 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;
|
||||
|
||||
//WIP: Mute if on B list (or not W list)
|
||||
char modeL[8];
|
||||
@@ -944,42 +1073,182 @@ 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;
|
||||
// }
|
||||
|
||||
//check to see if we need to enable slot and toggle slot preference here
|
||||
//if both groups allowed, then give no preference to either one (not sure this is needed now)
|
||||
// if ( (strcmp(modeL, "A") == 0) && (strcmp(modeR, "A") == 0) )
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 2;
|
||||
// }
|
||||
// else if (strcmp(modeL, "A") == 0)
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot_preference = 0;
|
||||
// }
|
||||
// else if (strcmp(modeR, "A") == 0)
|
||||
// {
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 1;
|
||||
// }
|
||||
// else //if any other condition, then give no preference to either one
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 2;
|
||||
// }
|
||||
|
||||
//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;
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
//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)
|
||||
{
|
||||
if (!encL)
|
||||
stereo_samp1[i*2+0] = state->s_l4[0][i];
|
||||
if (!encR)
|
||||
stereo_samp1[i*2+1] = state->s_r4[0][i];
|
||||
encL = 0;
|
||||
opts->slot1_on = 1;
|
||||
opts->slot_preference = 0;
|
||||
}
|
||||
else if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
{
|
||||
encR = 0;
|
||||
opts->slot2_on = 1;
|
||||
opts->slot_preference = 1;
|
||||
}
|
||||
else //otherwise, reset slot preference to either or (both slots enabled)
|
||||
{
|
||||
opts->slot_preference = 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 160; i++)
|
||||
//test hpf
|
||||
if (opts->use_hpf_d == 1)
|
||||
{
|
||||
if (!encL)
|
||||
stereo_samp2[i*2+0] = state->s_l4[1][i];
|
||||
if (!encR)
|
||||
stereo_samp2[i*2+1] = state->s_r4[1][i];
|
||||
hpf_dL(state, state->s_l4[0], 160);
|
||||
hpf_dL(state, state->s_l4[1], 160);
|
||||
hpf_dL(state, state->s_l4[2], 160);
|
||||
|
||||
hpf_dR(state, state->s_r4[0], 160);
|
||||
hpf_dR(state, state->s_r4[1], 160);
|
||||
hpf_dR(state, state->s_r4[2], 160);
|
||||
}
|
||||
|
||||
for (i = 0; i < 160; i++)
|
||||
//convert the left or right channel to both channels if single voice under certain conditions, if defined to do so
|
||||
#define DMR_STEREO_OUTPUT
|
||||
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
if (encL) memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
if (encR) memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
//this is for playing single voice over both channels, or when to keep them seperated
|
||||
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 both slots are the same now, then let's decimate the audio to keep the audio level consistent
|
||||
// if (memcmp (state->s_l4, state->s_r4, sizeof(state->s_l4)) == 0)
|
||||
// {
|
||||
// for (int j = 0; j < 3; j++)
|
||||
// {
|
||||
// for (i = 0; i < 160; i++)
|
||||
// {
|
||||
// state->s_l4[j][i] *= 0.85;
|
||||
// state->s_r4[j][i] *= 0.85;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
//check this last
|
||||
if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
{
|
||||
if (!encL)
|
||||
stereo_samp3[i*2+0] = state->s_l4[2][i];
|
||||
if (!encR)
|
||||
stereo_samp3[i*2+1] = state->s_r4[2][i];
|
||||
encL = 1;
|
||||
encR = 1;
|
||||
}
|
||||
|
||||
//at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
||||
if (encL && encR)
|
||||
goto SS3_END;
|
||||
|
||||
//test hpf
|
||||
// if (opts->use_hpf_d == 1)
|
||||
// {
|
||||
// hpf_dL(state, state->s_l4[0], 160);
|
||||
// hpf_dL(state, state->s_l4[1], 160);
|
||||
// hpf_dL(state, state->s_l4[2], 160);
|
||||
|
||||
// hpf_dR(state, state->s_r4[0], 160);
|
||||
// hpf_dR(state, state->s_r4[1], 160);
|
||||
// hpf_dR(state, state->s_r4[2], 160);
|
||||
// }
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encL)
|
||||
#endif
|
||||
stereo_samp1[i*2+0] = state->s_l4[0][i];
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encR)
|
||||
#endif
|
||||
stereo_samp1[i*2+1] = state->s_r4[0][i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encL)
|
||||
#endif
|
||||
stereo_samp2[i*2+0] = state->s_l4[1][i];
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encR)
|
||||
#endif
|
||||
stereo_samp2[i*2+1] = state->s_r4[1][i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encL)
|
||||
#endif
|
||||
stereo_samp3[i*2+0] = state->s_l4[2][i];
|
||||
#ifdef DMR_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encR)
|
||||
#endif
|
||||
stereo_samp3[i*2+1] = state->s_r4[2][i];
|
||||
}
|
||||
|
||||
if (opts->audio_out_type == 0) //Pulse Audio
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, stereo_samp1, 320*2, NULL);
|
||||
@@ -1007,9 +1276,9 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
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));
|
||||
//set short temp buffer to baseline
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
|
||||
if (state->audio_out_idx2 >= 800000)
|
||||
{
|
||||
@@ -1045,16 +1314,16 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
short stereo_samp2[320]; //8k 2-channel stereo interleave mix
|
||||
short stereo_samp3[320]; //8k 2-channel stereo interleave mix
|
||||
short stereo_samp4[320];
|
||||
|
||||
short empss[160]; //this is used to see if we want to run HPF on an empty set
|
||||
short empty[320]; //this is used to see if we want to play a single 2v or double 2v or not
|
||||
|
||||
memset (stereo_samp1, 1, sizeof(stereo_samp1));
|
||||
memset (stereo_samp2, 1, sizeof(stereo_samp2));
|
||||
memset (stereo_samp3, 1, sizeof(stereo_samp3));
|
||||
memset (stereo_samp4, 1, sizeof(stereo_samp4));
|
||||
memset (stereo_samp1, 0, sizeof(stereo_samp1));
|
||||
memset (stereo_samp2, 0, sizeof(stereo_samp2));
|
||||
memset (stereo_samp3, 0, sizeof(stereo_samp3));
|
||||
memset (stereo_samp4, 0, sizeof(stereo_samp4));
|
||||
|
||||
memset (empty, 1, sizeof(empty));
|
||||
|
||||
memset (empty, 0, sizeof(empty));
|
||||
memset (empss, 0, sizeof(empss));
|
||||
|
||||
//p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
encL = encR = 1;
|
||||
@@ -1137,6 +1406,24 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
||||
|
||||
//test hpf
|
||||
if (opts->use_hpf_d == 1)
|
||||
{
|
||||
hpf_dL(state, state->s_l4[0], 160);
|
||||
hpf_dL(state, state->s_l4[1], 160);
|
||||
if (memcmp(empss, state->s_l4[2], sizeof(empss)) != 0)
|
||||
hpf_dL(state, state->s_l4[2], 160);
|
||||
if (memcmp(empss, state->s_l4[3], sizeof(empss)) != 0)
|
||||
hpf_dL(state, state->s_l4[3], 160);
|
||||
|
||||
hpf_dR(state, state->s_r4[0], 160);
|
||||
hpf_dR(state, state->s_r4[1], 160);
|
||||
if (memcmp(empss, state->s_r4[2], sizeof(empss)) != 0)
|
||||
hpf_dR(state, state->s_r4[2], 160);
|
||||
if (memcmp(empss, state->s_r4[3], sizeof(empss)) != 0)
|
||||
hpf_dR(state, state->s_r4[3], 160);
|
||||
}
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
{
|
||||
@@ -1214,9 +1501,287 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
state->audio_out_idx = 0;
|
||||
state->audio_out_idxR = 0;
|
||||
|
||||
//set short temp buffer to baseline
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//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, 0, sizeof(stereo_sf));
|
||||
|
||||
short empty[320];
|
||||
memset (empty, 0, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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;
|
||||
// }
|
||||
|
||||
//check to see if we need to enable slot and toggle slot preference here
|
||||
//if both groups allowed, then give no preference to either one (not sure this is needed now)
|
||||
// if ( (strcmp(modeL, "A") == 0) && (strcmp(modeR, "A") == 0) )
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 2;
|
||||
// }
|
||||
// else if (strcmp(modeL, "A") == 0)
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot_preference = 0;
|
||||
// }
|
||||
// else if (strcmp(modeR, "A") == 0)
|
||||
// {
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 1;
|
||||
// }
|
||||
// else //if any other condition, then give no preference to either one
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 1;
|
||||
// opts->slot_preference = 2;
|
||||
// }
|
||||
|
||||
//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;
|
||||
}
|
||||
else if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
{
|
||||
encR = 0;
|
||||
opts->slot2_on = 1;
|
||||
opts->slot_preference = 1;
|
||||
}
|
||||
else //otherwise, reset slot preference to either or (both slots enabled)
|
||||
{
|
||||
opts->slot_preference = 2;
|
||||
}
|
||||
|
||||
//run hpf_d filter, if enabled
|
||||
if (opts->use_hpf_d == 1)
|
||||
{
|
||||
for (j = 0; j < 18; j++)
|
||||
{
|
||||
hpf_dL(state, state->s_l4[j], 160);
|
||||
hpf_dR(state, state->s_r4[j], 160);
|
||||
}
|
||||
}
|
||||
|
||||
//convert the left or right channel to both channels if single voice under certain conditions, if defined to do so
|
||||
#define P2_STEREO_OUTPUT
|
||||
|
||||
#ifdef P2_STEREO_OUTPUT
|
||||
if (encL) memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
if (encR) memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
//this is for playing single voice over both channels, or when to keep them seperated
|
||||
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 both slots are the same now, then let's decimate the audio to keep the audio level consistent
|
||||
// if (memcmp (state->s_l4, state->s_r4, sizeof(state->s_l4)) == 0)
|
||||
// {
|
||||
// for (j = 0; j < 18; j++)
|
||||
// {
|
||||
// for (i = 0; i < 160; i++)
|
||||
// {
|
||||
// state->s_l4[j][i] *= 0.85;
|
||||
// state->s_r4[j][i] *= 0.85;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
//check this last
|
||||
if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
{
|
||||
encL = 1;
|
||||
encR = 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++)
|
||||
{
|
||||
#ifdef P2_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encL)
|
||||
#endif
|
||||
stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
||||
#ifdef P2_STEREO_OUTPUT
|
||||
#else
|
||||
if (!encR)
|
||||
#endif
|
||||
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));
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
|
||||
if (state->audio_out_idx2 >= 800000)
|
||||
{
|
||||
@@ -1349,64 +1914,75 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot)
|
||||
|
||||
}
|
||||
|
||||
//the previous version, not quite as good at audio gain normalization, but keeping it just in case
|
||||
// void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot)
|
||||
// {
|
||||
// int i, run;
|
||||
// run = 1;
|
||||
// float empty[160];
|
||||
// memset (empty, 0.0f, sizeof(empty));
|
||||
//automatic gain short mono for analog audio and some digital mono (WIP)
|
||||
void agsm (dsd_opts * opts, dsd_state * state, short * input, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
// float mmax = 0.75f;
|
||||
// float mmin = -0.75f;
|
||||
// float aavg = 0.0f; //average of the absolute value
|
||||
// float df; //decimation value
|
||||
// df = 8000.0f; //test value -- this would be the ideal perfect value if everybody spoke directly into the mic at a reasonable volume
|
||||
UNUSED(opts);
|
||||
|
||||
// if (slot == 0)
|
||||
// df = (384.0f / (float)opts->pulse_digi_out_channels) * (50.0f - state->aout_gain);
|
||||
// if (slot == 1)
|
||||
// df = (384.0f / (float)opts->pulse_digi_out_channels) * (50.0f - state->aout_gainR);
|
||||
//NOTE: This seems to be doing better now that I got it worked out properly
|
||||
//This may produce a mild buzz sound though on the low end
|
||||
|
||||
// //this comparison is to determine whether or not to run gain on 'empty' samples (2v last 2, silent frames, etc)
|
||||
// if (memcmp(empty, samp, sizeof(empty)) == 0) run = 0;
|
||||
// if (run == 0) goto AGF_END;
|
||||
float avg = 0.0f; //average of 20 samples
|
||||
float coeff = 0.0f; //gain coeffiecient
|
||||
float max = 0.0f; //the highest sample value
|
||||
float nom = 4800.0f; //nominator value for 48k
|
||||
float samp[960]; memset (samp, 0.0f, 960*sizeof(float));
|
||||
|
||||
// for (i = 0; i < 160; i++)
|
||||
// {
|
||||
//assign internal float from short input
|
||||
for (i = 0; i < len; i++)
|
||||
samp[i] = (float)input[i];
|
||||
|
||||
// samp[i] = samp[i] / df;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if ( fabsf (samp[i]) > max)
|
||||
{
|
||||
max = fabsf (samp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// aavg += fabsf(samp[i]);
|
||||
for (i = 0; i < len; i++)
|
||||
avg += (float)samp[i];
|
||||
|
||||
// //simple clipping
|
||||
// if (samp[i] > mmax)
|
||||
// samp[i] = mmax;
|
||||
// if (samp[i] < mmin)
|
||||
// samp[i] = mmin;
|
||||
|
||||
// //may have been a tad too loud on the high end
|
||||
// // samp[i] *= 0.5f; //testing various values here
|
||||
|
||||
// }
|
||||
|
||||
// aavg /= 160.0f;
|
||||
|
||||
// if (slot == 0)
|
||||
// {
|
||||
// if (aavg < 0.075f && state->aout_gain < 42.0f) state->aout_gain += 1.0f;
|
||||
// if (aavg >= 0.075f && state->aout_gain > 1.0f) state->aout_gain -= 1.0f;
|
||||
// }
|
||||
|
||||
// if (slot == 1)
|
||||
// {
|
||||
// if (aavg < 0.075f && state->aout_gainR < 42.0f) state->aout_gainR += 1.0f;
|
||||
// if (aavg >= 0.075f && state->aout_gainR > 1.0f) state->aout_gainR -= 1.0f;
|
||||
// }
|
||||
|
||||
// //debug
|
||||
// // fprintf (stderr, "\nS%d - DF = %f AAVG = %f", slot, df, aavg);
|
||||
avg /= (float)len;
|
||||
|
||||
// AGF_END: ; //do nothing
|
||||
coeff = fabsf (nom / max);
|
||||
|
||||
// }
|
||||
//keep coefficient with tolerable range when silence to prevent crackle/buzz
|
||||
if (coeff > 3.0f) coeff = 3.0f;
|
||||
|
||||
//apply the coefficient to bring the max value to our desired maximum value
|
||||
for (i = 0; i < 20; i++)
|
||||
samp[i] *= coeff;
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "\n M: %f; C: %f; A: %f; ", max, coeff, avg);
|
||||
|
||||
// debug
|
||||
// for (i = 0; i < len; i++)
|
||||
// {
|
||||
// fprintf (stderr, " in: %d", input[i]);
|
||||
// fprintf (stderr, " out: %f", samp[i]);
|
||||
// }
|
||||
|
||||
//return new smaple values post agc
|
||||
for (i = 0; i < len; i++)
|
||||
input[i] = (short)samp[i];
|
||||
|
||||
state->aout_gainA = coeff; //store for internal use
|
||||
|
||||
}
|
||||
|
||||
//until analog agc is fixed, going to use a manual gain control on this
|
||||
void analog_gain (dsd_opts * opts, dsd_state * state, short * input, int len)
|
||||
{
|
||||
|
||||
int i;
|
||||
UNUSED(state);
|
||||
|
||||
float gain = (opts->audio_gainA / 100.0f) * 5.0f; //scale 0x - 5x
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
input[i] *= gain;
|
||||
}
|
||||
@@ -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) ||
|
||||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
|
||||
(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
|
||||
@@ -280,6 +281,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
// 29 -NXDN (inverted FSW)
|
||||
// 31 -YSF
|
||||
// 36 -P25p2
|
||||
// 77 -M17 BRT
|
||||
// 87 -M17 PKT
|
||||
// 99 -M17 Preamble
|
||||
|
||||
int valid;
|
||||
@@ -349,6 +352,8 @@ int digitize (dsd_opts* opts, dsd_state* state, int symbol)
|
||||
// 28 +NXND (FSW)
|
||||
// 30 +YSF
|
||||
// 35 +p25p2
|
||||
// 76 +M17 BRT
|
||||
// 86 +M17 PKT
|
||||
// 98 +M17 Preamble
|
||||
|
||||
int valid;
|
||||
|
||||
241
src/dsd_file.c
241
src/dsd_file.c
@@ -17,38 +17,6 @@
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
||||
char * getTimeF(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;
|
||||
}
|
||||
|
||||
char * getDateF(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 saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
@@ -128,86 +96,42 @@ void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
|
||||
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
unsigned char err;
|
||||
UNUSED(err);
|
||||
|
||||
err = (unsigned char) state->errs2;
|
||||
k = 0;
|
||||
if (opts->payload == 1) //print IMBE info
|
||||
fprintf(stderr, "\n IMBE ");
|
||||
uint8_t imbe[88];
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
fprintf(stderr, "\n IMBE ");
|
||||
}
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + imbe_d[k];
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%02X", b);
|
||||
}
|
||||
imbe[i] = convert_bits_into_output((uint8_t *)imbe_d+(i*8), 8);
|
||||
fprintf(stderr, "%02X", imbe[i]);
|
||||
}
|
||||
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
}
|
||||
|
||||
//fprintf (stderr, "\n");
|
||||
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
UNUSED(opts);
|
||||
}
|
||||
|
||||
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
unsigned char err;
|
||||
UNUSED(err);
|
||||
|
||||
err = (unsigned char) state->errs2;
|
||||
k = 0;
|
||||
//cast as unsigned long long int and not uint64_t
|
||||
//to avoid the %lx vs %llx warning on 32 or 64 bit
|
||||
unsigned long long int ambe = 0;
|
||||
|
||||
//preceeding line break, if required
|
||||
if (opts->dmr_stereo == 0 && opts->dmr_mono == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
if (opts->payload == 1) //print AMBE info from DMR Stereo method
|
||||
{
|
||||
fprintf(stderr, " AMBE ");
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1 && i < 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", b);
|
||||
}
|
||||
if (opts->payload == 1 && i == 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", b & 0x80);
|
||||
}
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
}
|
||||
else fprintf(stderr, " err = [%X] [%X] ", state->errsR, state->errs2R);
|
||||
b = ambe_d[48];
|
||||
if (opts->dmr_stereo == 1 || opts->dmr_mono == 1) //need to fix the printouts again
|
||||
{
|
||||
ambe = convert_bits_into_output ((uint8_t *)ambe_d, 49);
|
||||
ambe = ambe << 7; //shift to final position
|
||||
|
||||
fprintf(stderr, " AMBE %014llX", ambe);
|
||||
|
||||
if (state->currentslot == 0)
|
||||
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
|
||||
else fprintf(stderr, " err = [%X] [%X] ", state->errsR, state->errs2R);
|
||||
|
||||
//trailing line break, if required
|
||||
if (opts->dmr_stereo == 1 || opts->dmr_mono == 1)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -396,6 +320,11 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
int i, j;
|
||||
char ext[5];
|
||||
char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak
|
||||
char * datestr;
|
||||
|
||||
timestr = getTime();
|
||||
datestr = getDate();
|
||||
|
||||
//phase 1 and provoice
|
||||
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
|
||||
@@ -421,7 +350,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
|
||||
sprintf (opts->mbe_out_file, "%s %s S1%s", datestr, timestr, ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
||||
|
||||
@@ -436,6 +365,16 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (opts->mbe_out_f, "%s", ext);
|
||||
|
||||
fflush (opts->mbe_out_f);
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
@@ -443,6 +382,11 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
int i, j;
|
||||
char ext[5];
|
||||
char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak
|
||||
char * datestr;
|
||||
|
||||
timestr = getTime();
|
||||
datestr = getDate();
|
||||
|
||||
//phase 1 and provoice
|
||||
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
|
||||
@@ -468,7 +412,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
|
||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", datestr, timestr, ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
|
||||
|
||||
@@ -483,6 +427,16 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (opts->mbe_out_fR, "%s", ext);
|
||||
|
||||
fflush (opts->mbe_out_fR);
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
@@ -596,3 +550,86 @@ void closeSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
||||
opts->symbol_out_f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//input bit array, return output as up to a 64-bit value
|
||||
uint64_t convert_bits_into_output(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;
|
||||
}
|
||||
|
||||
void pack_bit_array_into_byte_array (uint8_t * input, uint8_t * output, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = (uint8_t)convert_bits_into_output(&input[i*8], 8);
|
||||
}
|
||||
|
||||
//take len amount of bits and pack into x amount of bytes (asymmetrical)
|
||||
void pack_bit_array_into_byte_array_asym (uint8_t * input, uint8_t * output, int len)
|
||||
{
|
||||
int i = 0; int k = len % 8;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
output[i/8] <<= 1;
|
||||
output[i/8] |= input[i];
|
||||
}
|
||||
//if any leftover bits that don't flush the last byte fully packed, shift them over left
|
||||
if (k)
|
||||
output[i/8] <<= 8-k;
|
||||
}
|
||||
|
||||
//take len amount of bytes and unpack back into a bit array
|
||||
void unpack_byte_array_into_bit_array (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;
|
||||
}
|
||||
}
|
||||
|
||||
//take len amount of bits and pack into x amount of bytes (asymmetrical)
|
||||
void pack_ambe (char * input, uint8_t * output, int len)
|
||||
{
|
||||
int i = 0; int k = len % 8;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
output[i/8] <<= 1;
|
||||
output[i/8] |= (uint8_t)input[i];
|
||||
}
|
||||
//if any leftover bits that don't flush the last byte fully packed, shift them over left
|
||||
if (k)
|
||||
output[i/8] <<= 8-k;
|
||||
}
|
||||
|
||||
//unpack byte array with ambe data into a 49-bit bitwise array
|
||||
void unpack_ambe (uint8_t * input, char * ambe)
|
||||
{
|
||||
int i = 0, k = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
ambe[k++] = (input[i] >> 7) & 1;
|
||||
ambe[k++] = (input[i] >> 6) & 1;
|
||||
ambe[k++] = (input[i] >> 5) & 1;
|
||||
ambe[k++] = (input[i] >> 4) & 1;
|
||||
ambe[k++] = (input[i] >> 3) & 1;
|
||||
ambe[k++] = (input[i] >> 2) & 1;
|
||||
ambe[k++] = (input[i] >> 1) & 1;
|
||||
ambe[k++] = (input[i] >> 0) & 1;
|
||||
}
|
||||
ambe[48] = input[6] >> 7;
|
||||
}
|
||||
@@ -1,29 +1,41 @@
|
||||
#include "dsd.h"
|
||||
|
||||
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
|
||||
#define M17ZEROS 80 //ONLY SEE 79 THOUGH
|
||||
float m17gain = 10.0f;
|
||||
static float m17xv[M17ZEROS+1];
|
||||
float m17coeffs[81] =
|
||||
#define M17ZEROS 80
|
||||
float m17gain = 3.16227766f; //sqrt of 10.0f
|
||||
static float m17xv[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.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299,
|
||||
0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372,
|
||||
-0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935,
|
||||
0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876,
|
||||
0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165,
|
||||
-0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576,
|
||||
-0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196,
|
||||
0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068,
|
||||
0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815,
|
||||
1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068,
|
||||
0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196,
|
||||
-0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576,
|
||||
-0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165,
|
||||
0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876,
|
||||
0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935,
|
||||
-0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372,
|
||||
-0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299,
|
||||
0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491,
|
||||
-0.001125978562075172, -0.006136551625729697, -0.009265784007800534
|
||||
-0.003195702904062073f, -0.002930279157647190f, -0.001940667871554463f,
|
||||
-0.000356087678023658f, 0.001547011339077758f, 0.003389554791179751f,
|
||||
0.004761898604225673f, 0.005310860846138910f, 0.004824746306020221f,
|
||||
0.003297923526848786f, 0.000958710871218619f, -0.001749908029791816f,
|
||||
-0.004238694106631223f, -0.005881783042101693f, -0.006150256456781309f,
|
||||
-0.004745376707651645f, -0.001704189656473565f, 0.002547854551539951f,
|
||||
0.007215575568844704f, 0.011231038205363532f, 0.013421952197060707f,
|
||||
0.012730475385624438f, 0.008449554307303753f, 0.000436744366018287f,
|
||||
-0.010735380379191660f, -0.023726883538258272f, -0.036498030780605324f,
|
||||
-0.046500883189991064f, -0.050979050575999614f, -0.047340680079891187f,
|
||||
-0.033554880492651755f, -0.008513823955725943f, 0.027696543159614194f,
|
||||
0.073664520037517042f, 0.126689053778116234f, 0.182990955139333916f,
|
||||
0.238080025892859704f, 0.287235637987091563f, 0.326040247765297220f,
|
||||
0.350895727088112619f, 0.359452932027607974f, 0.350895727088112619f,
|
||||
0.326040247765297220f, 0.287235637987091563f, 0.238080025892859704f,
|
||||
0.182990955139333916f, 0.126689053778116234f, 0.073664520037517042f,
|
||||
0.027696543159614194f, -0.008513823955725943f, -0.033554880492651755f,
|
||||
-0.047340680079891187f, -0.050979050575999614f, -0.046500883189991064f,
|
||||
-0.036498030780605324f, -0.023726883538258272f, -0.010735380379191660f,
|
||||
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
|
||||
@@ -244,4 +256,13 @@ dsd_input_filter(short sample, int mode)
|
||||
sum += (coeffs[i] * v[i]);
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -113,7 +113,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
return;
|
||||
}
|
||||
//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
|
||||
@@ -270,12 +270,18 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
return;
|
||||
}
|
||||
//M17
|
||||
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) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) ||
|
||||
(state->synctype == 76) || (state->synctype == 77) || (state->synctype == 86) || (state->synctype == 87) ||
|
||||
(state->synctype == 99) || (state->synctype == 98) )
|
||||
{
|
||||
if (state->synctype == 98 || state->synctype == 99) //preamble only
|
||||
skipDibit(opts, state, 8); //skip dibits to prime the demodulator
|
||||
else if (state->synctype == 16 || state->synctype == 17)
|
||||
processM17STR(opts, state);
|
||||
else if (state->synctype == 76 || state->synctype == 77) {} //Not available yet
|
||||
// processM17BRT(opts, state); //Not available yet
|
||||
else if (state->synctype == 86 || state->synctype == 87)
|
||||
processM17PKT(opts, state);
|
||||
else
|
||||
processM17LSF(opts, state);
|
||||
return;
|
||||
|
||||
@@ -18,59 +18,33 @@
|
||||
#include "dsd.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
|
||||
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
||||
{
|
||||
UNUSED3(state, offset, modulation);
|
||||
|
||||
char * timestr = getTimeC();
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"Sync: %s ", frametype);
|
||||
}
|
||||
if (opts->verbose > 2)
|
||||
{
|
||||
//fprintf (stderr,"o: %4i ", offset);
|
||||
}
|
||||
if (opts->verbose > 1)
|
||||
{
|
||||
//fprintf (stderr,"mod: %s ", modulation);
|
||||
}
|
||||
if (opts->verbose > 2)
|
||||
{
|
||||
//fprintf (stderr,"g: %f ", state->aout_gain);
|
||||
}
|
||||
{
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
fprintf (stderr,"Sync: %s ", frametype);
|
||||
}
|
||||
|
||||
//oops, that made a nested if-if-if-if statement,
|
||||
//causing a memory leak
|
||||
|
||||
// if (opts->verbose > 2)
|
||||
//fprintf (stderr,"o: %4i ", offset);
|
||||
// if (opts->verbose > 1)
|
||||
//fprintf (stderr,"mod: %s ", modulation);
|
||||
// if (opts->verbose > 2)
|
||||
//fprintf (stderr,"g: %f ", state->aout_gain);
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -184,10 +158,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
char synctest[25];
|
||||
char synctest12[13]; //dPMR
|
||||
char synctest10[11]; //NXDN FSW only
|
||||
char synctest18[19];
|
||||
char synctest32[33];
|
||||
char synctest20[21]; //YSF
|
||||
char synctest21[22]; //P25 S-OEMI (SACCH)
|
||||
char synctest48[49]; //EDACS
|
||||
char synctest8[9]; //M17
|
||||
char synctest16[17]; //M17 Preamble
|
||||
@@ -195,10 +167,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
char *synctest_p;
|
||||
char synctest_buf[10240]; //what actually is assigned to this, can't find its use anywhere?
|
||||
int lmin, lmax, lidx;
|
||||
UNUSED2(synctest18, synctest21);
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
t_max = 10;
|
||||
@@ -221,6 +192,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
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
|
||||
|
||||
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 +208,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
t = 0;
|
||||
synctest10[10] = 0;
|
||||
synctest[24] = 0;
|
||||
synctest8[8] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin)
|
||||
synctest12[12] = 0;
|
||||
synctest18[18] = 0;
|
||||
synctest16[16] = 0; //M17, wasn't initialized or terminated (source of much pain and frustration in Cygwin)
|
||||
synctest48[48] = 0;
|
||||
synctest32[32] = 0;
|
||||
synctest20[20] = 0;
|
||||
modulation[7] = 0; //not initialized or terminated (unsure if this would be an issue or not)
|
||||
synctest_pos = 0;
|
||||
synctest_p = synctest_buf + 10;
|
||||
sync = 0;
|
||||
@@ -613,6 +590,39 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
return (99);
|
||||
}
|
||||
}
|
||||
else if (strcmp(synctest8, M17_PKT) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+M17 PKT", 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 == 86 || state->lastsynctype == 8)
|
||||
{
|
||||
state->lastsynctype = 86;
|
||||
return (86);
|
||||
}
|
||||
state->lastsynctype = 86;
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
// else //unknown, -BRT?
|
||||
// {
|
||||
// printFrameSync (opts, state, "-M17 BRT", 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 == 77)
|
||||
// {
|
||||
// state->lastsynctype = 77;
|
||||
// return (77);
|
||||
// }
|
||||
// state->lastsynctype = 77;
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
}
|
||||
else if (strcmp(synctest8, M17_STR) == 0)
|
||||
{
|
||||
if (opts->inverted_m17 == 0)
|
||||
@@ -857,32 +867,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
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)
|
||||
{
|
||||
|
||||
102
src/dsd_gps.c
102
src/dsd_gps.c
@@ -119,10 +119,14 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
||||
FILE * pFile; //file pointer
|
||||
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
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() );
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
fprintf (pFile, "%s\t", timestr );
|
||||
fprintf (pFile, "%08d\t", add_hash);
|
||||
fprintf (pFile, "%.5lf\t", latitude);
|
||||
fprintf (pFile, "%.5lf\t", longitude);
|
||||
@@ -131,6 +135,17 @@ void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
|
||||
fprintf (pFile, "\n");
|
||||
fclose (pFile);
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -219,14 +234,18 @@ void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint
|
||||
FILE * pFile; //file pointer
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
|
||||
char * datestr = getDate();
|
||||
char * timestr = getTime();
|
||||
|
||||
int s = (int)fkph; //rounded interger format for the log report
|
||||
int a = 0;
|
||||
if (type == 2)
|
||||
a = nmea_cog; //long format only
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time if desired, but would require local user offset
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
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, "%.6lf\t", latitude);
|
||||
fprintf (pFile, "%.6lf\t", longitude);
|
||||
@@ -235,6 +254,17 @@ void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint
|
||||
fprintf (pFile, "\n");
|
||||
fclose (pFile);
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -337,14 +367,18 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t
|
||||
FILE * pFile; //file pointer
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
|
||||
char * datestr = getDate();
|
||||
char * timestr = getTime();
|
||||
|
||||
//rounded interger formats for the log report
|
||||
int s = (int)fkph;
|
||||
int a = nmea_cog;
|
||||
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time on PDU if desired
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
fprintf (pFile, "%s\t", timestr ); //could switch to UTC time on PDU if desired
|
||||
fprintf (pFile, "%08d\t", src);
|
||||
fprintf (pFile, "%.6lf\t", latitude);
|
||||
fprintf (pFile, "%.6lf\t", longitude);
|
||||
@@ -353,6 +387,17 @@ void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t
|
||||
fprintf (pFile, "\n");
|
||||
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
|
||||
@@ -464,10 +509,14 @@ void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
|
||||
FILE * pFile; //file pointer
|
||||
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
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() );
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
fprintf (pFile, "%s\t", timestr );
|
||||
fprintf (pFile, "%08d\t", src);
|
||||
fprintf (pFile, "%.6lf\t", lat_dec);
|
||||
fprintf (pFile, "%.6lf\t", lon_dec);
|
||||
@@ -476,6 +525,17 @@ void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
|
||||
fprintf (pFile, "\n");
|
||||
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
|
||||
@@ -561,14 +621,18 @@ void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
FILE * pFile; //file pointer
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
|
||||
char * datestr = getDate();
|
||||
char * timestr = getTime();
|
||||
|
||||
int src = 0;
|
||||
if (slot == 0) src = state->lasttg;
|
||||
if (slot == 1) src = state->lasttgR;
|
||||
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() );
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
fprintf (pFile, "%s\t", timestr );
|
||||
fprintf (pFile, "%08d\t", src);
|
||||
fprintf (pFile, "%.5lf\t", latitude);
|
||||
fprintf (pFile, "%.5lf\t", longitude);
|
||||
@@ -667,10 +731,13 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
if (slot == 0) src = state->lastsrc;
|
||||
if (slot == 1) src = state->lastsrcR;
|
||||
|
||||
char * datestr = getDate();
|
||||
char * timestr = getTime();
|
||||
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
fprintf (pFile, "%s\t", getDateL() );
|
||||
fprintf (pFile, "%s\t", getTimeL() );
|
||||
fprintf (pFile, "%s\t", datestr );
|
||||
fprintf (pFile, "%s\t", timestr );
|
||||
fprintf (pFile, "%08d\t", src);
|
||||
fprintf (pFile, "%.5lf\t", latitude);
|
||||
fprintf (pFile, "%.5lf\t", longitude);
|
||||
@@ -679,6 +746,17 @@ void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
fprintf (pFile, "\n");
|
||||
fclose (pFile);
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
if (datestr != NULL)
|
||||
{
|
||||
free (datestr);
|
||||
datestr = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
844
src/dsd_main.c
844
src/dsd_main.c
File diff suppressed because it is too large
Load Diff
250
src/dsd_mbe.c
250
src/dsd_mbe.c
@@ -79,7 +79,7 @@ int Pr[256] = {
|
||||
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
|
||||
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63
|
||||
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
|
||||
0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
|
||||
0x614C, 0x7E4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
|
||||
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
|
||||
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95
|
||||
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
|
||||
@@ -134,7 +134,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
|
||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
playSynthesizedVoiceMS (opts, state);
|
||||
}
|
||||
if (opts->floating_point == 1)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
|
||||
if (opts->audio_out == 1 && opts->floating_point == 0)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
playSynthesizedVoiceMS (opts, state);
|
||||
}
|
||||
if (opts->floating_point == 1)
|
||||
{
|
||||
@@ -257,9 +257,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
// 0 +P25p1
|
||||
// 1 -P25p1
|
||||
state->errs = mbe_eccImbe7200x4400C0 (imbe_fr);
|
||||
//state->errs2 = state->errs;
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateImbe7200x4400Data (imbe_fr);
|
||||
state->errs2 = mbe_eccImbe7200x4400Data (imbe_fr, imbe_d);
|
||||
state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr, imbe_d);
|
||||
|
||||
//P25p1 RC4 Handling
|
||||
if (state->payload_algid == 0xAA && state->R != 0)
|
||||
@@ -350,9 +350,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
|
||||
state->errs = mbe_eccImbe7100x4400C0 (imbe7100_fr);
|
||||
//state->errs2 = state->errs;
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateImbe7100x4400Data (imbe7100_fr);
|
||||
state->errs2 = mbe_eccImbe7100x4400Data (imbe7100_fr, imbe_d);
|
||||
state->errs2 += mbe_eccImbe7100x4400Data (imbe7100_fr, imbe_d);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -384,9 +384,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
|
||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
//state->errs2 = state->errs;
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateAmbe3600x2450Data (ambe_fr);
|
||||
state->errs2 = mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
|
||||
if ( (state->nxdn_cipher_type == 0x01 && state->R > 0) ||
|
||||
(state->M == 1 && state->R > 0) )
|
||||
@@ -428,9 +428,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
|
||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
//state->errs2 = state->errs;
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateAmbe3600x2450Data (ambe_fr);
|
||||
state->errs2 = mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
@@ -554,35 +554,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
rckey[7] = ((state->payload_mi & 0xFF00) >> 8);
|
||||
rckey[8] = ((state->payload_mi & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 9; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
//pack cipher byte array from ambe_d bit array
|
||||
pack_ambe(ambe_d, cipher, 49);
|
||||
|
||||
//only run keystream application if errs < 3 -- this is a fix to the pop sound
|
||||
//that may occur on some systems that preempt VC6 voice for a RC opportuninity (TXI)
|
||||
@@ -594,23 +567,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
|
||||
state->dropL += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p <= 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
//P25p2 RC4 Handling, VCH 0
|
||||
@@ -639,56 +599,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
rckey[11] = ((state->payload_miP & 0xFF00) >> 8);
|
||||
rckey[12] = ((state->payload_miP & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 13; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
//pack cipher byte array from ambe_d bit array
|
||||
pack_ambe(ambe_d, cipher, 49);
|
||||
|
||||
RC4(state->dropL, 13, 7, rckey, cipher, plain);
|
||||
state->dropL += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p <= 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
|
||||
@@ -714,9 +634,9 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
{
|
||||
|
||||
state->errsR = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
//state->errs2R = state->errsR;
|
||||
state->errs2R = state->errsR;
|
||||
mbe_demodulateAmbe3600x2450Data (ambe_fr);
|
||||
state->errs2R = mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
state->errs2R += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d);
|
||||
|
||||
//EXPERIMENTAL!!
|
||||
//load basic privacy key number from array by the tg value (if not forced)
|
||||
@@ -840,35 +760,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
rckey[7] = ((state->payload_miR & 0xFF00) >> 8);
|
||||
rckey[8] = ((state->payload_miR & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 9; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
//pack cipher byte array from ambe_d bit array
|
||||
pack_ambe(ambe_d, cipher, 49);
|
||||
|
||||
//only run keystream application if errs < 3 -- this is a fix to the pop sound
|
||||
//that may occur on some systems that preempt VC6 voice for a RC opportuninity (TXI)
|
||||
@@ -879,23 +772,10 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
else memcpy (plain, cipher, sizeof(plain));
|
||||
state->dropR += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p <= 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
//P25p2 RC4 Handling, VCH 1
|
||||
@@ -924,56 +804,16 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
rckey[11] = ((state->payload_miN & 0xFF00) >> 8);
|
||||
rckey[12] = ((state->payload_miN & 0xFF) >> 0);
|
||||
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// fprintf (stderr, "%s", KYEL);
|
||||
// fprintf (stderr, " RC4K ");
|
||||
// for (short o = 0; o < 13; o++)
|
||||
// {
|
||||
// fprintf (stderr, "%02X", rckey[o]);
|
||||
// }
|
||||
// fprintf (stderr, "%s", KNRM);
|
||||
// fprintf (stderr, "\n");
|
||||
// }
|
||||
|
||||
short k = 0;
|
||||
for (short o = 0; o < 7; o++)
|
||||
{
|
||||
short b = 0;
|
||||
for (short p = 0; p < 8; p++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
if (k == 49)
|
||||
{
|
||||
cipher[6] = ((b << 3) & 0x80); //set 7th octet/bit 49 accordingly
|
||||
break;
|
||||
}
|
||||
}
|
||||
cipher[o] = b;
|
||||
}
|
||||
//pack cipher byte array from ambe_d bit array
|
||||
pack_ambe(ambe_d, cipher, 49);
|
||||
|
||||
RC4(state->dropR, 13, 7, rckey, cipher, plain);
|
||||
state->dropR += 7;
|
||||
|
||||
short z = 0;
|
||||
for (short p = 0; p <= 6; p++)
|
||||
{
|
||||
//convert bytes back to bits and load into ambe_d array.
|
||||
short b = 0; //reset b to use again
|
||||
for (short o = 0; o < 8; o++)
|
||||
{
|
||||
b = (( (plain[p] << o) & 0x80) >> 7);
|
||||
ambe_d[z] = b;
|
||||
z++;
|
||||
if (z == 49)
|
||||
{
|
||||
ambe_d[48] = ( (plain[p] << o) & 0x80);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//unpack deciphered plain array back into ambe_d bit array
|
||||
memset (ambe_d, 0, 49*sizeof(char));
|
||||
unpack_ambe(plain, ambe_d);
|
||||
|
||||
}
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR,
|
||||
@@ -1071,17 +911,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
fprintf (stderr, " *OFF*");
|
||||
}
|
||||
|
||||
state->debug_audio_errors += state->errs2 + state->errs;
|
||||
state->debug_audio_errors += state->errs2;
|
||||
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
if ( opts->floating_point == 0 ) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices
|
||||
{
|
||||
#ifdef AERO_BUILD
|
||||
if(opts->audio_out == 1 && opts->slot1_on == 1) //add conditional check here, otherwise some lag occurs on dual voices with OSS48k/1 input due to buffered audio
|
||||
#endif
|
||||
processAudio(opts, state);
|
||||
}
|
||||
if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot1_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible
|
||||
{
|
||||
playSynthesizedVoice (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead
|
||||
playSynthesizedVoiceMS (opts, state); //it may be more beneficial to move this to each individual decoding type to handle, but ultimately, let's just simpifly mbe handling instead
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1145,17 +988,20 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
fprintf (stderr, " *OFF*");
|
||||
}
|
||||
|
||||
state->debug_audio_errorsR += state->errs2R + state->errsR;
|
||||
state->debug_audio_errorsR += state->errs2R;
|
||||
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
if ( opts->floating_point == 0) //opts->audio_out == 1 && //needed to remove for AERO OSS so we could still save wav files during dual voices
|
||||
{
|
||||
#ifdef AERO_BUILD
|
||||
if(opts->audio_out == 1 && opts->slot2_on == 1) //add conditional check here, otherwise some lag occurs on dual voices with OSS48k/1 input due to buffered audio
|
||||
#endif
|
||||
processAudioR(opts, state);
|
||||
}
|
||||
if (opts->audio_out == 1 && opts->floating_point == 0 && opts->audio_out_type == 5 && opts->slot2_on == 1) //for OSS 48k 1 channel configs -- relocate later if possible
|
||||
{
|
||||
playSynthesizedVoiceR (opts, state);
|
||||
playSynthesizedVoiceMSR (opts, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,7 +1012,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
//if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types
|
||||
if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
|
||||
{
|
||||
state->debug_audio_errors += state->errs2 + state->errs;
|
||||
state->debug_audio_errors += state->errs2;
|
||||
if (opts->audio_out == 1 && opts->floating_point == 0 ) //&& opts->pulse_digi_rate_out == 8000
|
||||
{
|
||||
processAudio(opts, state);
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
void soft_demod_imbe7200 (dsd_state * state, char imbe_fr7200[8][23], char imbe_d[88])
|
||||
{
|
||||
state->errs = mbe_eccImbe7200x4400C0 (imbe_fr7200);
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateImbe7200x4400Data (imbe_fr7200);
|
||||
state->errs2 = mbe_eccImbe7200x4400Data (imbe_fr7200, imbe_d);
|
||||
state->debug_audio_errors += state->errs2 + state->errs;
|
||||
state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr7200, imbe_d);
|
||||
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])
|
||||
{
|
||||
state->errs = mbe_eccImbe7100x4400C0 (imbe_fr7100);
|
||||
state->errs2 = state->errs;
|
||||
mbe_demodulateImbe7100x4400Data (imbe_fr7100);
|
||||
state->errs2 = mbe_eccImbe7100x4400Data (imbe_fr7100, imbe_d);
|
||||
state->debug_audio_errors += state->errs2 + state->errs;
|
||||
state->errs2 += mbe_eccImbe7100x4400Data (imbe_fr7100, imbe_d);
|
||||
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])
|
||||
{
|
||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe2_ehr);
|
||||
state->errs2 = state->errs;
|
||||
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);
|
||||
|
||||
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)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
@@ -135,7 +138,7 @@ void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char amb
|
||||
PrintAMBEData (opts, state, ambe_d);
|
||||
|
||||
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)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
|
||||
1257
src/dsd_ncurses.c
1257
src/dsd_ncurses.c
File diff suppressed because it is too large
Load Diff
215
src/dsd_rigctl.c
215
src/dsd_rigctl.c
@@ -31,6 +31,8 @@ void error(char *msg) {
|
||||
}
|
||||
|
||||
struct sockaddr_in address;
|
||||
struct sockaddr_in addressA;
|
||||
struct sockaddr_in addressM17;
|
||||
|
||||
//
|
||||
// Connect
|
||||
@@ -133,7 +135,7 @@ bool SetFreq(int sockfd, long int freq)
|
||||
Send(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 true;
|
||||
@@ -143,11 +145,19 @@ bool SetModulation(int sockfd, int bandwidth)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
//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);
|
||||
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 true;
|
||||
@@ -250,6 +260,12 @@ int UDPBind (char *hostname, int portno)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -283,7 +299,7 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
|
||||
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);
|
||||
size_t err = 0;
|
||||
@@ -291,16 +307,16 @@ int udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * d
|
||||
//listen with:
|
||||
|
||||
//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
|
||||
//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
|
||||
//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
|
||||
//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
|
||||
err = sendto(opts->udp_sockfd, data, nsam, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
|
||||
@@ -308,6 +324,49 @@ 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
|
||||
}
|
||||
|
||||
int m17_socket_receiver(dsd_opts * opts, void * data)
|
||||
{
|
||||
size_t err = 0;
|
||||
struct sockaddr_in cliaddr;
|
||||
socklen_t len = sizeof(cliaddr);
|
||||
|
||||
//receive data from socket
|
||||
err = recvfrom(opts->udp_sockfd, data, 1000, 0, (struct sockaddr * ) & address, &len); //was MSG_WAITALL, but that seems to be = 256
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
//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 m17_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
|
||||
{
|
||||
UNUSED(state);
|
||||
unsigned long long int err = 0;
|
||||
|
||||
//See notes in m17.c on line ~3395 regarding usage
|
||||
|
||||
//send audio or data to socket
|
||||
err = sendto(opts->m17_udp_sock, data, nsam, 0, (const struct sockaddr * ) & addressM17, sizeof(struct sockaddr_in));
|
||||
//RETURN Value should be ACKN or NACK, or PING, or PONG
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
UNUSED(state);
|
||||
@@ -345,4 +404,144 @@ int udp_socket_connect(dsd_opts * opts, dsd_state * state)
|
||||
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;
|
||||
}
|
||||
|
||||
int udp_socket_connectM17(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
UNUSED(state);
|
||||
|
||||
long int err = 0;
|
||||
err = opts->m17_udp_sock = 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->m17_udp_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
memset((char * ) & addressM17, 0, sizeof(addressM17));
|
||||
addressM17.sin_family = AF_INET;
|
||||
err = addressM17.sin_addr.s_addr = inet_addr(opts->m17_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);
|
||||
}
|
||||
|
||||
addressM17.sin_port = htons(opts->m17_portno);
|
||||
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->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 ");
|
||||
}
|
||||
|
||||
106
src/dsd_symbol.c
106
src/dsd_symbol.c
@@ -17,29 +17,6 @@
|
||||
|
||||
#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
|
||||
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);
|
||||
//update root means square power level
|
||||
opts->rtl_rms = rtl_return_rms();
|
||||
sample *= opts->rtl_volume_multiplier;
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -222,6 +200,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
#else
|
||||
result = sf_read_short(opts->tcp_file_in, &sample, 1);
|
||||
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");
|
||||
sample = 0;
|
||||
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 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
|
||||
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
|
||||
if (have_sync == 0)
|
||||
{
|
||||
|
||||
//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))
|
||||
{
|
||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||
state->analog_sample_counter = 0;
|
||||
}
|
||||
// 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));
|
||||
// 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
|
||||
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)
|
||||
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
|
||||
|
||||
//debug
|
||||
// opts->rtl_rms = 101;
|
||||
//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
|
||||
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
|
||||
// for (int x = 0; x < 960; x++)
|
||||
// state->analog_out[x] /= 4;
|
||||
//low pass filter
|
||||
if (opts->use_lpf == 1)
|
||||
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
|
||||
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)
|
||||
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
|
||||
|
||||
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
|
||||
|
||||
@@ -322,12 +332,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
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
|
||||
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);
|
||||
}
|
||||
//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)
|
||||
// {
|
||||
// sf_write_short(opts->wav_out_raw, state->analog_out, 960);
|
||||
// sf_write_sync (opts->wav_out_raw);
|
||||
// }
|
||||
|
||||
memset (state->analog_out, 0, sizeof(state->analog_out));
|
||||
state->analog_sample_counter = 0;
|
||||
@@ -367,7 +377,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
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);
|
||||
}
|
||||
@@ -647,8 +658,15 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
|
||||
fclose(opts->symbolfile);
|
||||
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
|
||||
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
|
||||
openPulseInput(opts); //open pulse input
|
||||
|
||||
71
src/dsd_time.c
Normal file
71
src/dsd_time.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
@@ -1,158 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dsd_upsample.c
|
||||
* 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
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
* LWVMOBILE
|
||||
* 2024-03 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#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)
|
||||
void upsampleS (short invalue, short prev, short outbuf[6])
|
||||
{
|
||||
UNUSED(prev);
|
||||
for (int i = 0; i < 6; i++)
|
||||
outbuf[i] = invalue;
|
||||
}
|
||||
|
||||
float c, d;
|
||||
//legacy 6x simplified version for the float_buf_p
|
||||
void upsample (dsd_state * state, float invalue)
|
||||
{
|
||||
|
||||
c = prev;
|
||||
d = invalue;
|
||||
float *outbuf1;
|
||||
if (state->currentslot == 0 && state->dmr_stereo == 1)
|
||||
outbuf1 = state->audio_out_float_buf_p;
|
||||
|
||||
// basic triangle interpolation
|
||||
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));
|
||||
outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
||||
outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
||||
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;
|
||||
}
|
||||
@@ -328,7 +328,7 @@ void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
|
||||
fprintf (stderr, "; ");
|
||||
|
||||
//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
|
||||
|
||||
|
||||
@@ -436,10 +436,10 @@ decode_bch()
|
||||
d[u + 1] = alpha_to[s[u + 1]];
|
||||
else
|
||||
d[u + 1] = 0;
|
||||
for (i = 1; i <= l[u + 1]; i++)
|
||||
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
||||
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
||||
+ index_of[elp[u + 1][i]]) % n];
|
||||
for (i = 1; i <= l[u + 1]; i++)
|
||||
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
||||
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
||||
+ index_of[elp[u + 1][i]]) % n];
|
||||
/* put d[u+1] into index form */
|
||||
d[u + 1] = index_of[d[u + 1]];
|
||||
}
|
||||
|
||||
2118
src/edacs-fme.c
2118
src/edacs-fme.c
File diff suppressed because it is too large
Load Diff
17
src/fec.c
17
src/fec.c
@@ -1308,12 +1308,12 @@ void Golay_24_12_init()
|
||||
}
|
||||
}
|
||||
|
||||
// Not very efficient but encode is used for unit testing only
|
||||
// Not very efficient but encode is used for unit testing only, I think this is wrong for M17
|
||||
void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
|
||||
memset(encodedBits, 0, 24);
|
||||
// memset(encodedBits, 0, 24);
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -1326,7 +1326,7 @@ void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
encodedBits[i] %= 2;
|
||||
// fprintf (stderr, "%b", encodedBits[i]); //disable later on
|
||||
// fprintf (stderr, "%b", encodedBits[i]); //disable later on
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1475,10 +1475,11 @@ void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits)
|
||||
|
||||
bool QR_16_7_6_decode(unsigned char *rxBits)
|
||||
{
|
||||
//2 bit errors or less
|
||||
unsigned int syndromeI = 0; // syndrome index
|
||||
int is = 0;
|
||||
int i = 0;
|
||||
|
||||
int corrections = 0;
|
||||
for (is = 0; is < 9; is++)
|
||||
{
|
||||
syndromeI += (((rxBits[0] * QR_16_7_6_m_H[16*is + 0])
|
||||
@@ -1512,6 +1513,7 @@ bool QR_16_7_6_decode(unsigned char *rxBits)
|
||||
else
|
||||
{
|
||||
rxBits[QR_16_7_6_m_corr[syndromeI][i]] ^= 1; // flip bit
|
||||
corrections++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1519,8 +1521,15 @@ bool QR_16_7_6_decode(unsigned char *rxBits)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//disabling again for now
|
||||
// if (corrections > 1) //no more than 1-bit error, else consider failure?
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,8 +166,8 @@ void CNXDNConvolution_start(void)
|
||||
|
||||
void CNXDNConvolution_init()
|
||||
{
|
||||
memset(m_metrics1, 0xFF, 16*sizeof(uint16_t));
|
||||
memset(m_metrics2, 0xFF, 16*sizeof(uint16_t));
|
||||
// memset(m_decisions,0xFF, 8*300*sizeof(uint64_t));
|
||||
memset(m_metrics1, 0x0, 16*sizeof(uint16_t));
|
||||
memset(m_metrics2, 0x0, 16*sizeof(uint16_t));
|
||||
memset(m_decisions,0x0, 8*300*sizeof(uint64_t));
|
||||
}
|
||||
|
||||
|
||||
@@ -280,6 +280,8 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
}
|
||||
|
||||
fprintf (stderr, "PF 1/1");
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
|
||||
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
|
||||
@@ -331,6 +333,11 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
fprintf (stderr, "PF %d/4", part_of_frame+1);
|
||||
if (part_of_frame == 0)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
// if (crc != check)
|
||||
// {
|
||||
@@ -340,7 +347,33 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
|
||||
// }
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
// if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
//this seems to work much better now
|
||||
else if (part_of_frame != 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
|
||||
//advance seed by required number of turns depending on the current pf value
|
||||
int start = 0; int end = part_of_frame;
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
for (start = 0; start < end; start++)
|
||||
{
|
||||
//run 4 times
|
||||
LFSRN(ambe_temp, ambe_d, state);
|
||||
LFSRN(ambe_temp, ambe_d, state);
|
||||
LFSRN(ambe_temp, ambe_d, state);
|
||||
LFSRN(ambe_temp, ambe_d, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (crc == check)
|
||||
{
|
||||
@@ -568,7 +601,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int cac_fail = 0;
|
||||
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
{
|
||||
uint8_t deperm[300]; //300
|
||||
@@ -684,6 +717,49 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
//check for accumulative cac failures and reset if multiple errors pile up
|
||||
//(LZ issue and also issue very occasssionally noticed on remote)
|
||||
if (crc != 0) cac_fail++;
|
||||
else cac_fail = 0;
|
||||
|
||||
//reset some parameters if CAC continues to fail
|
||||
if (cac_fail > 10)
|
||||
{
|
||||
//simple reset
|
||||
state->synctype = 0;
|
||||
state->lastsynctype = -1;
|
||||
state->carrier = 0;
|
||||
state->last_cc_sync_time = time(NULL)+2; //probably not necesary
|
||||
cac_fail = 0; //reset
|
||||
|
||||
//more advanced modulator reset
|
||||
state->center = 0;
|
||||
state->jitter = -1;
|
||||
state->synctype = -1;
|
||||
state->min = -15000;
|
||||
state->max = 15000;
|
||||
state->lmid = 0;
|
||||
state->umid = 0;
|
||||
state->minref = -12000;
|
||||
state->maxref = 12000;
|
||||
state->lastsample = 0;
|
||||
for (int i = 0; i < 128; i++) state->sbuf[i] = 0;
|
||||
state->sidx = 0;
|
||||
for (int i = 0; i < 1024; i++) state->maxbuf[i] = 15000;
|
||||
for (int i = 0; i < 1024; i++) state->minbuf[i] = -15000;
|
||||
state->midx = 0;
|
||||
state->symbolcnt = 0;
|
||||
|
||||
//reset the dibit buffer
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->offset = 0;
|
||||
|
||||
//debug notification
|
||||
// fprintf (stderr, " RESET CARRIER; ");
|
||||
|
||||
}
|
||||
|
||||
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
|
||||
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
|
||||
|
||||
@@ -816,7 +892,14 @@ void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint
|
||||
else part_of_frame = 0;
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
// if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
|
||||
|
||||
//reset scrambler seed to key value on new superframe
|
||||
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1)
|
||||
{
|
||||
if (state->nxdn_cipher_type == 1 && state->R != 0) state->payload_miN = state->R; //reset scrambler seed
|
||||
else if (state->M == 1 && state->R != 0) state->payload_miN = state->R; //force reset scrambler seed
|
||||
}
|
||||
|
||||
/*
|
||||
4.3.2. Mapping to Functional Channel
|
||||
|
||||
@@ -150,9 +150,9 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
NXDN_decode_VCALL(opts, state, ElementsContent);
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
|
||||
#ifdef LIMAZULUTWEAKS
|
||||
; //do nothing -- testing errors on CAC messages when returning quickly from RTCH
|
||||
#else
|
||||
// #ifdef LIMAZULUTWEAKS
|
||||
// ; //do nothing -- testing errors on CAC messages when returning quickly from RTCH
|
||||
// #else
|
||||
|
||||
//tune back to CC here - save about 1-2 seconds
|
||||
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
|
||||
@@ -197,7 +197,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
state->last_cc_sync_time = time(NULL); //allow tuners a second to catch up, particularly rtl input
|
||||
}
|
||||
|
||||
#endif
|
||||
// #endif
|
||||
break;
|
||||
|
||||
//Idle
|
||||
@@ -647,6 +647,10 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
state->nxdn_last_tg = DestinationID;
|
||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
|
||||
//Call String for Per Call WAV File
|
||||
sprintf (state->call_string[0], "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
if (CCOption & 0x80) strcat (state->call_string[0], " Emergency");
|
||||
|
||||
//check the rkey array for a scrambler key value
|
||||
//TGT ID and Key ID could clash though if csv or system has both with different keys
|
||||
if (state->rkey_array[DestinationID] != 0)
|
||||
@@ -654,6 +658,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
state->R = state->rkey_array[DestinationID];
|
||||
fprintf (stderr, " %s", KYEL);
|
||||
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
|
||||
state->payload_miN = state->R; //should be okay to load here, will test
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
}
|
||||
@@ -680,6 +685,10 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
state->nxdn_last_tg = DestinationID;
|
||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
|
||||
//Call String for Per Call WAV File
|
||||
sprintf (state->call_string[0], "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
if (CCOption & 0x80) strcat (state->call_string[0], " Emergency");
|
||||
|
||||
//check the rkey array for a scrambler key value
|
||||
//TGT ID and Key ID could clash though if csv or system has both with different keys
|
||||
if (state->rkey_array[DestinationID] != 0)
|
||||
@@ -687,6 +696,7 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
|
||||
state->R = state->rkey_array[DestinationID];
|
||||
fprintf (stderr, " %s", KYEL);
|
||||
fprintf (stderr, " Key Loaded: %lld", state->rkey_array[DestinationID]);
|
||||
state->payload_miN = state->R; //should be okay to load here, will test
|
||||
}
|
||||
if (state->M == 1) state->nxdn_cipher_type = 0x1;
|
||||
#endif
|
||||
@@ -1213,6 +1223,11 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
if(CCOption & 0x40) fprintf(stderr, "Visitor ");
|
||||
if(CCOption & 0x20) fprintf(stderr, "Priority Paging ");
|
||||
|
||||
//Call String for Per Call WAV File
|
||||
sprintf (state->call_string[0], "%s", NXDN_Call_Type_To_Str(CallType));
|
||||
if (CCOption & 0x80) strcat (state->call_string[0], " Emergency");
|
||||
if (CipherType) strcat (state->call_string[0], " Enc");
|
||||
|
||||
if((CipherType == 2) || (CipherType == 3))
|
||||
{
|
||||
state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1;
|
||||
|
||||
@@ -419,6 +419,11 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
//roll the voice scrambler LFSR here if key available to advance seed (usually just needed on NXDN96)
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
|
||||
{
|
||||
if (state->payload_miN == 0)
|
||||
{
|
||||
state->payload_miN = state->R;
|
||||
}
|
||||
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -436,6 +441,11 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
|
||||
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
|
||||
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
|
||||
{
|
||||
if (state->payload_miN == 0)
|
||||
{
|
||||
state->payload_miN = state->R;
|
||||
}
|
||||
|
||||
char ambe_temp[49] = {0};
|
||||
char ambe_d[49] = {0};
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
||||
@@ -68,7 +68,7 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182
|
||||
if (voice == 2) start = 2;
|
||||
if (voice == 2 || voice == 3) stop = 4;
|
||||
|
||||
for (start; start < stop; start++)
|
||||
for (; start < stop; start++)
|
||||
{
|
||||
w = nW;
|
||||
x = nX;
|
||||
@@ -93,7 +93,7 @@ void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182
|
||||
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
|
||||
|
||||
if (opts->floating_point == 0 )
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
|
||||
(Channel Spacing) x (0.125 kHz).
|
||||
*/
|
||||
|
||||
//return 0 if channel value is 0 or 0xFFFF
|
||||
if (channel == 0) return 0;
|
||||
if (channel == 0xFFFF) return 0;
|
||||
|
||||
//Note: Base Frequency is calculated as (Base Frequency) x (0.000005 MHz) from the IDEN_UP message.
|
||||
|
||||
long int freq = -1;
|
||||
@@ -90,8 +94,8 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
|
||||
else base = 0; //just set to zero, will be system definable most likely and won't be able to calc
|
||||
|
||||
//determine the step value in Hz
|
||||
if (state->nxdn_step = 2) step = 1250; //1.25 kHz
|
||||
else if (state->nxdn_step = 3) step = 3125; //3.125 kHz
|
||||
if (state->nxdn_step == 2) step = 1250; //1.25 kHz
|
||||
else if (state->nxdn_step == 3) step = 3125; //3.125 kHz
|
||||
else step = 0; //just set to zero, will be system definable most likely and won't be able to calc
|
||||
|
||||
//if we have a valid base and step, then calc frequency
|
||||
|
||||
@@ -147,15 +147,19 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
|
||||
else if (lc_format == 0x49)
|
||||
{
|
||||
fprintf (stderr, " Souce ID Extension");
|
||||
fprintf (stderr, " Source ID Extension -");
|
||||
uint32_t nid = (uint32_t)ConvertBitIntoBytes(&LCW_bits[16], 24);
|
||||
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
|
||||
fprintf (stderr, " Full SUID: %08X-%08d", nid, src);
|
||||
|
||||
}
|
||||
|
||||
else if (lc_format == 0x4A)
|
||||
{
|
||||
fprintf (stderr, " Unit to Unit Voice Channel User – Extended");
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[16], 24);
|
||||
uint32_t suid = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
|
||||
fprintf (stderr, "TGT: %04X SUID: %d; ", target, suid);
|
||||
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
|
||||
fprintf (stderr, "TGT: %d; SRC: %d; ", target, src);
|
||||
}
|
||||
|
||||
else if (lc_format == 0x50)
|
||||
@@ -209,6 +213,8 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
fprintf (stderr, " System Service Broadcast");
|
||||
}
|
||||
|
||||
//this PDU does not have an associated MFID, often seen on kiwi and matches its TSBK counterpart
|
||||
//its possible some of the other ones here don't as well, need to re-check all of them
|
||||
else if (lc_format == 0x61)
|
||||
{
|
||||
fprintf (stderr, " Secondary Control Channel Broadcast");
|
||||
@@ -393,6 +399,14 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
uint32_t base = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 32);
|
||||
fprintf (stderr, " Channel Identifier Update VU; Iden: %X; Base: %d;", iden, base*5);
|
||||
}
|
||||
|
||||
//This lc_format doesn't use the MFID field
|
||||
else if (lc_format == 0x61)
|
||||
fprintf (stderr, " Secondary Control Channel Broadcast");
|
||||
|
||||
//This lc_format doesn't use the MFID field
|
||||
else if (lc_format == 0x62)
|
||||
fprintf (stderr, " Adjacent Site Status Broadcast");
|
||||
|
||||
//This lc_format doesn't use the MFID field
|
||||
else if (lc_format == 0x63)
|
||||
@@ -406,10 +420,28 @@ void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t ir
|
||||
}
|
||||
|
||||
else if (lc_mfid == 0x90 && lc_opcode == 0x0)
|
||||
{
|
||||
//needed to fill this in, since tuning this on P1 will just leave the TG/SRC as zeroes
|
||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel User (LCGRGR)");
|
||||
uint32_t sg = (uint32_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
|
||||
uint32_t src = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
|
||||
fprintf (stderr, " SG: %d; SRC: %d;", sg, src);
|
||||
if (LCW_bits[16] == 1) fprintf (stderr, " Res;"); //res bit (octet 2)
|
||||
if (LCW_bits[17] == 1) fprintf (stderr, " ENC;"); //P-bit (octet 2)
|
||||
if (LCW_bits[31] == 1) fprintf (stderr, " EXT;"); //Full SUID next LC (external) (octet 3)
|
||||
state->lasttg = sg;
|
||||
state->lastsrc = src;
|
||||
}
|
||||
|
||||
else if (lc_mfid == 0x90 && lc_opcode == 0x1)
|
||||
{
|
||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Channel Update (LCGRGU)");
|
||||
uint32_t sg = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
|
||||
uint32_t ch = (uint32_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
|
||||
fprintf (stderr, " SG: %d; CH: %04X;", sg, ch);
|
||||
if (LCW_bits[16] == 1) fprintf (stderr, " Res;"); //res bit (octet 2)
|
||||
if (LCW_bits[17] == 1) fprintf (stderr, " ENC;"); //P-bit (octet 2)
|
||||
}
|
||||
|
||||
else if (lc_mfid == 0x90 && lc_opcode == 0x3)
|
||||
fprintf (stderr, " MFID90 (Moto) Group Regroup Add");
|
||||
|
||||
@@ -145,9 +145,22 @@ process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count)
|
||||
}
|
||||
}
|
||||
|
||||
/* //this is what is observed on the sigid wiki example (matches above pattern)
|
||||
IMBE 000F920291AD6F06540980 err = [3] [A]
|
||||
IMBE 000F920294816F06540980 err = [3] [A]
|
||||
IMBE 000E1C0294816F06540980 err = [3] [B]
|
||||
|
||||
//this is what is observed on the 'hole' examples (not a match, TODO: Examine imbe_fr add this?)
|
||||
IMBE FC00000000000000000300 err = [2] [B]
|
||||
IMBE FC00000000000000000300 err = [2] [B]
|
||||
IMBE FC00000000000000000300 err = [2] [B]
|
||||
|
||||
*/
|
||||
|
||||
if (match) {
|
||||
// Skip this particular value. If we let it pass it will be signaled as an erroneus IMBE
|
||||
fprintf (stderr, "(Non-standard IMBE c0 detected, skipped)");
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n IMBE Non-standard c0 detected, skipped;");
|
||||
} else {
|
||||
processMbeFrame (opts, state, imbe_fr, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -74,7 +74,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -95,7 +95,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -116,7 +116,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -137,7 +137,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -158,7 +158,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -179,7 +179,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -200,7 +200,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -261,7 +261,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
|
||||
@@ -65,7 +65,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -79,7 +79,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -100,7 +100,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -121,7 +121,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -142,7 +142,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -163,7 +163,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -184,7 +184,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
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)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
|
||||
@@ -203,7 +203,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -264,7 +264,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
#endif
|
||||
process_IMBE (opts, state, &status_count);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 1)
|
||||
@@ -627,6 +627,47 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
#define P25p1_ENC_LO //disable if this behavior is detremental
|
||||
#ifdef P25p1_ENC_LO
|
||||
//If trunking and tuning ENC calls is disabled, lock out and go back to CC
|
||||
int enc_lo = 1; int ttg = state->lasttg; //checking to a valid TG will help make sure we have a good LDU1 LCW or HDU first
|
||||
if (irrecoverable_errors == 0 && state->payload_algid != 0x80 && state->payload_algid != 0 && opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && opts->trunk_tune_enc_calls == 0)
|
||||
{
|
||||
//NOTE: This may still cause an issue IF we havent' loaded the key yet from keyloader
|
||||
if (state->payload_algid == 0xAA && state->R != 0) enc_lo = 0;
|
||||
// else if (future condition) enc_lo = 0;
|
||||
// else if (future condition) enc_lo = 0;
|
||||
|
||||
//if this is locked out by conditions above, then write it into the TG mode if we have a TG value assigned
|
||||
if (enc_lo == 1 && ttg != 0)
|
||||
{
|
||||
int xx = 0; int enc_wr = 0;
|
||||
for (xx = 0; xx < state->group_tally; xx++)
|
||||
{
|
||||
if (state->group_array[xx].groupNumber == ttg)
|
||||
{
|
||||
enc_wr = 1; //already in there, so no need to assign it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if not already in there, so save it there now
|
||||
if (enc_wr == 0)
|
||||
{
|
||||
state->group_array[state->group_tally].groupNumber = ttg;
|
||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO"); //was xx and not state->group_tally
|
||||
state->group_tally++;
|
||||
}
|
||||
|
||||
//return to the control channel
|
||||
fprintf (stderr, " No Enc Following on P25p1 Trunking; Return to CC; \n");
|
||||
return_to_cc (opts, state);
|
||||
}
|
||||
}
|
||||
#endif //P25p1_ENC_LO
|
||||
|
||||
}
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
|
||||
226
src/p25p1_mdpu.c
226
src/p25p1_mdpu.c
@@ -3,7 +3,7 @@
|
||||
* P25p1 Multi Block PDU and Multi Block Trunking
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-12 DSD-FME Florida Man Edition
|
||||
* 2024-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
@@ -38,6 +38,8 @@ void processSAP(uint8_t SAP, char * sap_string)
|
||||
else if (SAP == 4) sprintf (sap_string, " Packet Data;");
|
||||
else if (SAP == 5) sprintf (sap_string, " Address Resolution Protocol;");
|
||||
else if (SAP == 6) sprintf (sap_string, " SNDCP Packet Data Control;");
|
||||
else if (SAP == 15) sprintf (sap_string, " Packet Data Scan Preamble;");
|
||||
else if (SAP == 29) sprintf (sap_string, " Packet Data Encryption Support;");
|
||||
else if (SAP == 31) sprintf (sap_string, " Extended Address;");
|
||||
else if (SAP == 32) sprintf (sap_string, " Registration and Authorization;");
|
||||
else if (SAP == 33) sprintf (sap_string, " Channel Reassignment;");
|
||||
@@ -49,6 +51,7 @@ void processSAP(uint8_t SAP, char * sap_string)
|
||||
else if (SAP == 39) sprintf (sap_string, " Mobile Radio Configuration;");
|
||||
else if (SAP == 40) sprintf (sap_string, " Unencrypted Key Management;");
|
||||
else if (SAP == 41) sprintf (sap_string, " Encrypted Key Management;");
|
||||
else if (SAP == 48) sprintf (sap_string, " Location Service;");
|
||||
else if (SAP == 61) sprintf (sap_string, " Trunking Control;");
|
||||
else if (SAP == 63) sprintf (sap_string, " Encrypted Trunking Control;");
|
||||
|
||||
@@ -77,6 +80,13 @@ static uint32_t crc32mbf(uint8_t * buf, int len)
|
||||
void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//p25p2 18v reset counters and buffers
|
||||
state->voice_counter[0] = 0; //reset
|
||||
state->voice_counter[1] = 0; //reset
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
opts->slot_preference = 2;
|
||||
|
||||
//reset some strings when returning from a call in case they didn't get zipped already
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
@@ -140,7 +150,6 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
uint8_t opcode = 0;
|
||||
|
||||
uint32_t address = 0; //source, or destination address depending on the io bit (outbound is target)
|
||||
// uint32_t target2 = 0; //enhanced addressing source value found in a second 1/2 rate header
|
||||
uint8_t fmf = 0;
|
||||
uint8_t pad = 0;
|
||||
uint8_t ns = 0;
|
||||
@@ -194,9 +203,6 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
// if (dibit == 2) fprintf (stderr, " Unknown - Use for Inbound or Outbound;");
|
||||
// if (dibit == 3) fprintf (stderr, " Inbound Channel Idle;");
|
||||
|
||||
//this is used to skip gathering one dibit as well since we only will end up skipping 2 status dibits (getting 99 instead of 98, throwing alignment off)
|
||||
// if (i > 92) start = 1; //testing values (i > 101-(36*3)-101)? may need longer 3/4 rata messages for comparison/correction (fall back to this if issues arise)
|
||||
// else start = 0;
|
||||
}
|
||||
|
||||
skipdibit++; //increment
|
||||
@@ -332,8 +338,6 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s",KRED);
|
||||
fprintf (stderr, " P25 Data Header CRC Error");
|
||||
fprintf (stderr, "%s",KNRM);
|
||||
//Don't add to the data call string, can occur when tuning from control channel with MBT blocks
|
||||
// sprintf (state->dmr_lrrp_gps[0], "Data Call: Header Error; Unknown Format/SAP;");
|
||||
end = 1; //go ahead and end after this loop
|
||||
}
|
||||
|
||||
@@ -504,16 +508,6 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
@@ -569,8 +563,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
int channelt = (mpdu_byte[22] << 8) | mpdu_byte[23];
|
||||
int channelr = (mpdu_byte[24] << 8) | mpdu_byte[25]; //optional!
|
||||
//using source and target address, not source and target id (is this correct?)
|
||||
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
|
||||
long int source = (mpdu_byte[3] << 16) | (mpdu_byte[4] << 8) | mpdu_byte[5];
|
||||
long int target = (mpdu_byte[19] << 16) |(mpdu_byte[20] << 8) | mpdu_byte[21];
|
||||
//TODO: Test Full Values added here for SUID, particular tgt_nid and tgt_sid
|
||||
long int src_nid = (mpdu_byte[12] << 24) | (mpdu_byte[13] << 16) | (mpdu_byte[14] << 8) | mpdu_byte[15];
|
||||
long int src_sid = (mpdu_byte[16] << 16) | (mpdu_byte[17] << 8) | mpdu_byte[18];
|
||||
long int tgt_nid = (mpdu_byte[26] << 16) | (mpdu_byte[27] << 8) | mpdu_byte[28]; //only has 3 octets on tgt nid, partial only?
|
||||
long int tgt_sid = (mpdu_byte[29] << 16) | (mpdu_byte[30] << 8) | mpdu_byte[31];
|
||||
long int freq1 = 0;
|
||||
long int freq2 = 0;
|
||||
UNUSED(freq2);
|
||||
@@ -587,7 +586,7 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
|
||||
}
|
||||
fprintf (stderr, " Unit to Unit Voice Channel Grant Update - Extended");
|
||||
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Source [%ld][%04lX] Target [%ld][%04lX]", svc, channelt, channelr, source, source, target, target);
|
||||
fprintf (stderr, "\n SVC: %02X; CHAN-T: %04X; CHAN-R: %04X; SRC: %ld; TGT: %ld; FULL SRC: %08lX-%08ld; FULL TGT: %08lX-%08ld;", svc, channelt, channelr, source, target, src_nid, src_sid, tgt_nid, tgt_sid);
|
||||
freq1 = process_channel_to_freq (opts, state, channelt);
|
||||
freq2 = process_channel_to_freq (opts, state, channelr); //optional!
|
||||
|
||||
@@ -621,17 +620,6 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
|
||||
{
|
||||
|
||||
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
|
||||
// if (opts->mod_qpsk == 1)
|
||||
// {
|
||||
// int spacing = state->p25_chan_spac[channelt >> 12];
|
||||
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
|
||||
// {
|
||||
// state->samplesPerSymbol = 8;
|
||||
// state->symbolCenter = 3;
|
||||
// }
|
||||
// }
|
||||
|
||||
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
|
||||
if (1 == 1)
|
||||
{
|
||||
@@ -727,13 +715,8 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
//TG hold on UU_V -- will want to disable UU_V grants while TG Hold enabled -- same for Telephone?
|
||||
//TG hold on UU_V -- will want to disable UU_V grants while TG Hold enabled
|
||||
if (state->tg_hold != 0 && state->tg_hold != target) sprintf (mode, "%s", "B");
|
||||
// if (state->tg_hold != 0 && state->tg_hold == target)
|
||||
// {
|
||||
// sprintf (mode, "%s", "A");
|
||||
// opts->p25_is_tuned = 0; //unlock tuner
|
||||
// }
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
@@ -922,17 +905,11 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
|
||||
else
|
||||
{
|
||||
//convert mpdu_byte to vPDU format and get indication of what the message was
|
||||
PDU[0] = 0x0C; //P25p1 MB Duid 0x0C
|
||||
PDU[1] = opcode;
|
||||
PDU[2] = MFID;
|
||||
PDU[1] = PDU[1] ^ 0xC0; //flip bits to make it compatible with MAC_PDUs explicit format
|
||||
|
||||
//without any extra bytes filled in, we can atleast see what the MBT is supposed to be
|
||||
//Hopefully, no 0 value things will cause issues -- call grants, iden_up, etc!
|
||||
// fprintf (stderr, "%s",KYEL);
|
||||
// process_MAC_VPDU(opts, state, 0, PDU);
|
||||
// fprintf (stderr, "%s",KNRM);
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n MFID %02X (Unknown); Opcode: %02X; ", MFID, mpdu_byte[0] & 0x3F);
|
||||
for (i = 0; i < (12*(blks+1)%37); i++)
|
||||
fprintf (stderr, "%02X", mpdu_byte[i]);
|
||||
fprintf (stderr, " %s",KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,15 +919,17 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n P25 MBT Payload \n ");
|
||||
for (i = 0; i < 36; i++)
|
||||
for (i = 0; i < ((blks+1)*12); i++)
|
||||
{
|
||||
if ( (i != 0) && ((i % 12) == 0))
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", mpdu_byte[i]);
|
||||
if (i == 11 || i == 23) fprintf (stderr, "\n ");
|
||||
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, " CRC EXT %08X CMP %08X", CRCExtracted, CRCComputed);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
fprintf (stderr, "\n ");
|
||||
|
||||
//Header
|
||||
if (err[0] != 0)
|
||||
@@ -977,27 +956,51 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
else if (r34 == 1 && err[0] == 0) //start 34 rate dump if good header crc
|
||||
{
|
||||
|
||||
//ES Auxiliary Header
|
||||
if (sap == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
unsigned long long int mi = (unsigned long long int)ConvertBitIntoBytes(&mpdu_crc_bits[0], 64);
|
||||
uint8_t mi_res = (uint8_t)ConvertBitIntoBytes(&mpdu_crc_bits[64], 8);
|
||||
uint8_t alg_id = (uint8_t)ConvertBitIntoBytes(&mpdu_crc_bits[72], 8);
|
||||
uint16_t key_id = (uint16_t)ConvertBitIntoBytes(&mpdu_crc_bits[80], 16);
|
||||
fprintf (stderr, "\n ALG: %02X; KEY ID: %04X; MI: %016llX; ", alg_id, key_id, mi);
|
||||
if (mi_res != 0)
|
||||
fprintf (stderr, "RES: %02X;", mi_res);
|
||||
|
||||
//The Auxiliary Header signals the actual SAP value of the encrypted message (this byte is not encrypted)
|
||||
uint8_t aux_res = (uint8_t)ConvertBitIntoBytes(&mpdu_crc_bits[96], 2); //these two bits should always be signalled as 1's, so 0b11, and if combined with the 2ndary SAP, 0xC0 if SAP == 0x00
|
||||
uint8_t aux_sap = (uint8_t)ConvertBitIntoBytes(&mpdu_crc_bits[98], 6); //the SAP of the message that is encrypted immediately after
|
||||
char aux_sap_string[99];
|
||||
processSAP (aux_sap, aux_sap_string);
|
||||
fprintf (stderr, "%s",KNRM);
|
||||
UNUSED(aux_res);
|
||||
}
|
||||
|
||||
// if (opts->payload == 1) //always dump these for now since users are actively choosing to tune to these grants
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n P25 MPDU 34 Rate Payload \n ");
|
||||
for (i = 0; i < 12; i++) //header
|
||||
fprintf (stderr, "[%02X]", mpdu_byte[i]);
|
||||
fprintf (stderr, "%02X", mpdu_byte[i]);
|
||||
fprintf (stderr, " Header \n ");
|
||||
|
||||
memset (mpdu_byte, 0, sizeof(mpdu_byte));
|
||||
for (i = 0; i < 16*10; i++) //16*(blks+1)
|
||||
for (i = 0; i < 16*(blks+1); i++) //16*10
|
||||
mpdu_byte[i] = (uint8_t)ConvertBitIntoBytes(&mpdu_crc_bits[i*8], 8);
|
||||
|
||||
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&mpdu_crc_bits[(128*blks)-32], 32);
|
||||
CRCComputed = crc32mbf(mpdu_byte, (128*blks)-32);
|
||||
if (CRCComputed == CRCExtracted) err[1] = 0;
|
||||
|
||||
//reset mpdu_byte to load only the data, and not the dbsn and crc into
|
||||
memset (mpdu_byte, 0, sizeof(mpdu_byte));
|
||||
int mpdu_idx = 0;
|
||||
int next = 0;
|
||||
//variable len printing
|
||||
for (i = 2; i <= 18*blks; i++) //<= only because we want that final DBSN/CRC9 printed out
|
||||
{
|
||||
if (i == 18 || i == 36 || i == 54 || i == 72 || i == 90)
|
||||
if ( (i != 0) && ((i % 18) == 0))
|
||||
{
|
||||
uint8_t dbsn = r34bytes[i-18] >> 1; //get the previous DBSN at this point
|
||||
uint16_t crc9_ext = ((r34bytes[i-18] & 1) << 8) | r34bytes[i-17];
|
||||
@@ -1015,7 +1018,8 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
if (i != 18*blks) i += 2; //skip the next DBSN/CRC9
|
||||
if (i != 18*blks) fprintf (stderr, "\n ");
|
||||
}
|
||||
if (i != 18*blks) fprintf (stderr, "[%02X]", r34bytes[i]);
|
||||
if (i != 18*blks) fprintf (stderr, "%02X", r34bytes[i]);
|
||||
mpdu_byte[mpdu_idx++] = r34bytes[i];
|
||||
}
|
||||
|
||||
if (err[1] != 0)
|
||||
@@ -1025,20 +1029,53 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, " CRC EXT %08X CMP %08X", CRCExtracted, CRCComputed);
|
||||
}
|
||||
else //testing for grins
|
||||
dmr_pdu (opts, state, blks*16, mpdu_byte);
|
||||
// else
|
||||
// TODO: decode PDU function
|
||||
|
||||
#define P25_ASCII_TEST34
|
||||
#ifdef P25_ASCII_TEST34
|
||||
// if (sap == 0) //user data
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n P25 MPDU ASCII: ");
|
||||
for (i = 0; i < (16*blks)-4; i++)
|
||||
start = 0; //offset for any sort of aux headers
|
||||
if (sap == 1) start = 13;
|
||||
for (i = start; i < mpdu_idx-pad-4; i++)
|
||||
{
|
||||
if (mpdu_byte[i] <= 0x7E && mpdu_byte[i] >=0x20)
|
||||
fprintf (stderr, "%c", mpdu_byte[i]);
|
||||
else fprintf (stderr, " ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// #define P25_UTF16_TEST
|
||||
#ifdef P25_UTF16_TEST
|
||||
//utf-16 text messaging (debug)
|
||||
// if (utf-16)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n P25 MPDU UTF16: ");
|
||||
uint16_t ch16 = 0;
|
||||
start = 0; //offset for any sort of aux headers
|
||||
if (sap == 1) start = 13;
|
||||
for (i = start; i < mpdu_idx-pad-4;)
|
||||
{
|
||||
ch16 = (uint16_t)mpdu_byte[i+0];
|
||||
ch16 <<= 8;
|
||||
ch16 |= (uint16_t)mpdu_byte[i+1];
|
||||
// fprintf (stderr, " %04X; ", ch16); //debug for raw values to check grouping for offset
|
||||
|
||||
if (ch16 >= 0x20) //if not a linebreak or terminal commmands
|
||||
fprintf (stderr, "%lc", ch16);
|
||||
else if (ch16 == 0) //if padding
|
||||
fprintf (stderr, "_");
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
@@ -1056,6 +1093,28 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else err[1] = 0; //No CRC32 on a lonely header
|
||||
|
||||
//ES Auxiliary Header (need to find samples to confirm presence and correctness on 1/2 rate data)
|
||||
if (sap == 1 && blks != 0) //may not need blocks check, since if this is present, multiple blocks will be required
|
||||
{
|
||||
fprintf (stderr, "%s",KYEL);
|
||||
unsigned long long int mi = ((unsigned long long int)mpdu_byte[12] << 56ULL) | ((unsigned long long int)mpdu_byte[13] << 48ULL) | ((unsigned long long int)mpdu_byte[14] << 40ULL) | ((unsigned long long int)mpdu_byte[15] << 32ULL) |
|
||||
((unsigned long long int)mpdu_byte[16] << 24ULL) | ((unsigned long long int)mpdu_byte[17] << 16ULL) | ((unsigned long long int)mpdu_byte[18] << 8ULL) | ((unsigned long long int)mpdu_byte[19] << 0ULL);
|
||||
uint8_t mi_res = mpdu_byte[20];
|
||||
uint8_t alg_id = mpdu_byte[21];
|
||||
uint16_t key_id = (mpdu_byte[22] << 8) | mpdu_byte[23];
|
||||
fprintf (stderr, "\n ALG: %02X; KEY ID: %04X; MI: %016llX; ", alg_id, key_id, mi);
|
||||
if (mi_res != 0)
|
||||
fprintf (stderr, "RES: %02X;", mi_res);
|
||||
|
||||
//The Auxiliary Header signals the actual SAP value of the encrypted message (this byte is not encrypted)
|
||||
uint8_t aux_res = mpdu_byte[24] >> 6; //these two bits should always be signalled as 1's, so 0b11, and if combined with the 2ndary SAP, 0xC0 if SAP == 0x00
|
||||
uint8_t aux_sap = mpdu_byte[24] & 0x3F; //the SAP of the message that is encrypted immediately after
|
||||
char aux_sap_string[99];
|
||||
processSAP (aux_sap, aux_sap_string);
|
||||
fprintf (stderr, "%s",KNRM);
|
||||
UNUSED(aux_res);
|
||||
}
|
||||
|
||||
// if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
@@ -1063,9 +1122,9 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
for (i = 0; i < 12*(blks+1); i++) //header and payload combined
|
||||
{
|
||||
if (i == 12) fprintf (stderr, " Header");
|
||||
if (i == 12 || i == 24 || i == 36 || i == 48 || i == 60 || i == 72 || i == 84 || i == 90)
|
||||
if ( (i != 0) && ((i % 12) == 0))
|
||||
fprintf (stderr, "\n ");
|
||||
fprintf (stderr, "[%02X]", mpdu_byte[i]);
|
||||
fprintf (stderr, "%02X", mpdu_byte[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1076,8 +1135,53 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, " CRC EXT %08X CMP %08X", CRCExtracted, CRCComputed);
|
||||
}
|
||||
else if (blks != 0) //testing for grins
|
||||
dmr_pdu (opts, state, blks*16, mpdu_byte);
|
||||
// else if (blks != 0)
|
||||
// TODO: decode PDU function
|
||||
|
||||
#define P25_ASCII_TEST12
|
||||
#ifdef P25_ASCII_TEST12
|
||||
// if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%s",KCYN);
|
||||
fprintf (stderr, "\n P25 MPDU ASCII: ");
|
||||
start = 0; //offset for any sort of aux headers
|
||||
if (sap == 1) start = 13;
|
||||
for (i = start; i < (12*(blks+1))-4-pad; i++)
|
||||
{
|
||||
if (mpdu_byte[i] <= 0x7E && mpdu_byte[i] >=0x20)
|
||||
fprintf (stderr, "%c", mpdu_byte[i]);
|
||||
else fprintf (stderr, " ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// #define P25_UTF16_TEST12
|
||||
#ifdef P25_UTF16_TEST12
|
||||
//utf-16 text messaging (debug)
|
||||
// if (utf-16)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n P25 MPDU UTF16: ");
|
||||
uint16_t ch16 = 0;
|
||||
start = 0; //offset for any sort of aux headers
|
||||
if (sap == 1) start = 13;
|
||||
for (i = start; i < (12*blks)-4-pad;)
|
||||
{
|
||||
ch16 = (uint16_t)mpdu_byte[i+0];
|
||||
ch16 <<= 8;
|
||||
ch16 |= (uint16_t)mpdu_byte[i+1];
|
||||
// fprintf (stderr, " %04X; ", ch16); //debug for raw values to check grouping for offset
|
||||
|
||||
if (ch16 >= 0x20) //if not a linebreak or terminal commmands
|
||||
fprintf (stderr, "%lc", ch16);
|
||||
else if (ch16 == 0) //if padding
|
||||
fprintf (stderr, "_");
|
||||
else fprintf (stderr, " ");
|
||||
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf (stderr, "%s",KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//p25p2 18v reset counters and buffers
|
||||
state->voice_counter[0] = 0; //reset
|
||||
state->voice_counter[1] = 0; //reset
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
opts->slot_preference = 2;
|
||||
|
||||
|
||||
//reset some strings when returning from a call in case they didn't get zipped already
|
||||
sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
@@ -386,7 +394,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//Skip tuning encrypted calls if enc calls are disabled
|
||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
// if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
|
||||
//tune if tuning available
|
||||
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -630,6 +645,70 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define P25p2_ENC_LO //disable if this behavior is detremental
|
||||
#ifdef P25p2_ENC_LO
|
||||
|
||||
//If trunking and tuning ENC calls is disabled, lock out and go back to CC
|
||||
int enc_lo = 1;
|
||||
int ttg = 0; //checking to a valid TG will help make sure we have a good MAC_PTT or SACCH Channel Update First
|
||||
int alg = 0; //set alg and key based on current slot values
|
||||
unsigned long long int key = 0;
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
ttg = state->lasttg;
|
||||
alg = state->payload_algid;
|
||||
if (alg == 0xAA) key = state->R;
|
||||
// else if (future condition) key = 1;
|
||||
// else if (future condition) key = 1;
|
||||
}
|
||||
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
ttg = state->lasttgR;
|
||||
alg = state->payload_algidR;
|
||||
if (alg == 0xAA) key = state->RR;
|
||||
// else if (future condition) key = 1;
|
||||
// else if (future condition) key = 1;
|
||||
}
|
||||
|
||||
if (alg != 0 && opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && opts->trunk_tune_enc_calls == 0)
|
||||
{
|
||||
//NOTE: This may still cause an issue IF we havent' loaded the key yet from keyloader
|
||||
if (alg == 0xAA && key != 0) enc_lo = 0;
|
||||
// else if (future condition) enc_lo = 0;
|
||||
// else if (future condition) enc_lo = 0;
|
||||
|
||||
//if this is locked out by conditions above, then write it into the TG mode if we have a TG value assigned
|
||||
if (enc_lo == 1 && ttg != 0)
|
||||
{
|
||||
int xx = 0; int enc_wr = 0;
|
||||
for (xx = 0; xx < state->group_tally; xx++)
|
||||
{
|
||||
if (state->group_array[xx].groupNumber == ttg)
|
||||
{
|
||||
enc_wr = 1; //already in there, so no need to assign it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if not already in there, so save it there now
|
||||
if (enc_wr == 0)
|
||||
{
|
||||
state->group_array[state->group_tally].groupNumber = ttg;
|
||||
sprintf (state->group_array[state->group_tally].groupMode, "%s", "DE");
|
||||
sprintf (state->group_array[state->group_tally].groupName, "%s", "ENC LO"); //was xx and not state->group_tally
|
||||
state->group_tally++;
|
||||
}
|
||||
|
||||
//return to the control channel -- NOTE: Disabled, just mark as lockout for now, return would require complex check of the other slot activity
|
||||
// fprintf (stderr, " No Enc Following on P25p2 Trunking; Return to CC; \n");
|
||||
// return_to_cc (opts, state);
|
||||
}
|
||||
}
|
||||
#endif //P25p2_ENC_LO
|
||||
|
||||
}
|
||||
if (ec == -1 || ec >= 15)
|
||||
{
|
||||
@@ -709,17 +788,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 +815,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
|
||||
@@ -756,22 +846,6 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
vc_counter = 0;
|
||||
int err_counter = 0;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
for (ts_counter = 0; ts_counter < 4; ts_counter++) //12
|
||||
{
|
||||
duid_decoded = -2;
|
||||
@@ -794,9 +868,18 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
duid_decoded = duid_lookup[p2_duid_complete];
|
||||
|
||||
char * timestr = getTimeC();
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"%s ", timestr);
|
||||
fprintf (stderr, " P25p2 ");
|
||||
|
||||
if (timestr != NULL)
|
||||
{
|
||||
free (timestr);
|
||||
timestr = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (state->currentslot == 0 && duid_decoded != 3 && duid_decoded != 12 && duid_decoded != 13 && duid_decoded != 4)
|
||||
{
|
||||
@@ -844,6 +927,20 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
opts->p25_is_tuned = 0;
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
|
||||
memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine
|
||||
//clear out stale voice samples left in the buffer and reset counter value
|
||||
state->voice_counter[0] = 0;
|
||||
state->voice_counter[1] = 0;
|
||||
memset(state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset(state->s_r4, 0, sizeof(state->s_r4));
|
||||
}
|
||||
else if (duid_decoded == 13 && ((time(NULL) - state->last_active_time) > 2) && opts->p25_is_tuned == 0) //should we use && opts->p25_is_tuned == 1?
|
||||
{
|
||||
memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine
|
||||
//clear out stale voice samples left in the buffer and reset counter value
|
||||
state->voice_counter[0] = 0;
|
||||
state->voice_counter[1] = 0;
|
||||
memset(state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset(state->s_r4, 0, sizeof(state->s_r4));
|
||||
}
|
||||
|
||||
if (duid_decoded == 0)
|
||||
@@ -930,6 +1027,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 +1048,22 @@ 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)
|
||||
{
|
||||
//debug test, see what each counter is at during playback on dual voice
|
||||
// fprintf (stderr, " VC1: %02d; VC2: %02d;", state->voice_counter[0], state->voice_counter[1] );
|
||||
|
||||
playSynthesizedVoiceSS18 (opts, state);
|
||||
state->voice_counter[0] = 0; //reset
|
||||
state->voice_counter[1] = 0; //reset
|
||||
}
|
||||
|
||||
//debug: fix burst indicator for ncurses if marginal signal
|
||||
// if (voice)
|
||||
|
||||
355
src/p25p2_vpdu.c
355
src/p25p2_vpdu.c
@@ -21,7 +21,7 @@ static const uint8_t mac_msg_len[256] = {
|
||||
8, 18, 0, 7, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, //8F (needed to add 81 and 8f for Harris)
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //9F
|
||||
16, 0, 0, 11, 13, 11, 11, 11, 10, 0, 0, 0, 0, 0, 0, 0, //AF
|
||||
17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //BF, B0 was 0, set to 17 (Harris again)
|
||||
17, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //BF, B0 was 0, set to 17 (Harris again), B5 Tait 0, set to 5
|
||||
11, 0, 0, 8, 15, 12, 15, 32, 12, 12, 0, 27, 14, 29, 29, 32, //CF
|
||||
0, 0, 0, 0, 0, 0, 9, 0, 14, 29, 11, 27, 14, 0, 40, 11, //DF
|
||||
28, 0, 0, 14, 17, 14, 0, 0, 16, 8, 11, 0, 13, 19, 0, 0, //EF
|
||||
@@ -154,16 +154,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -254,16 +254,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -315,11 +315,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n MFID90 Group Regroup Channel Grant Update");
|
||||
fprintf (stderr, "\n Channel 1 [%04X] Group 1 [%d][%04X]", channel1, group1, group1);
|
||||
freq1 = process_channel_to_freq (opts, state, channel1);
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
if (channel2 != channel1 && channel2 != 0 && channel2 != 0xFFFF)
|
||||
{
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
}
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; Ch: %04X SG: %d; ", channel1, group1, channel2, group2);
|
||||
if (channel2 != channel1 && channel2 != 0 && channel2 != 0xFFFF)
|
||||
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; Ch: %04X SG: %d; ", channel1, group1, channel2, group2);
|
||||
else sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; ", channel1, group1);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
@@ -385,16 +390,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -510,16 +515,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -641,16 +646,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;
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -690,16 +695,31 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
|
||||
//Unit-to-Unit Voice Service Channel Grant (UU_V_CH_GRANT), or Grant Update (same format)
|
||||
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46) //double check these opcodes
|
||||
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46 || MAC[1+len_a] == 0xC4) //double check these opcodes
|
||||
{
|
||||
int channel = (MAC[2+len_a] << 8) | MAC[3+len_a];
|
||||
int target = (MAC[4+len_a] << 16) | (MAC[5+len_a] << 8) | MAC[6+len_a];
|
||||
int source = (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | MAC[9+len_a];
|
||||
unsigned long long int src_suid = 0;
|
||||
long int freq = 0;
|
||||
|
||||
if (MAC[1+len_a] == 0x21)
|
||||
{
|
||||
src_suid = (MAC[6+len_a] << 48ULL) | (MAC[7+len_a] << 40ULL) | (MAC[8+len_a] << 32ULL) | (MAC[9+len_a] << 24ULL) |
|
||||
(MAC[10+len_a] << 16ULL) | (MAC[11+len_a] << 8ULL) | (MAC[12+len_a] << 0ULL);
|
||||
|
||||
source = src_suid & 0xFFFFFF;
|
||||
|
||||
target = (MAC[13+len_a] << 16) | (MAC[14+len_a] << 8) | MAC[15+len_a];
|
||||
|
||||
// channel = (MAC[4+len_a] << 8) | MAC[5+len_a]; //CH-R, above is CH-T value
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n Unit to Unit Channel Grant");
|
||||
if ( MAC[1+len_a] == 0x46) fprintf (stderr, " Update");
|
||||
fprintf (stderr, "\n CHAN [%04X] Source [%d] Target [%d]", channel, source, target);
|
||||
if ( MAC[1+len_a] == 0xC4) fprintf (stderr, " Extended");
|
||||
fprintf (stderr, "\n CHAN: %04X; SRC: %d; TGT: %d; ", channel, source, target);
|
||||
if (MAC[1+len_a] == 0xC4) fprintf (stderr, "SUID: %08llX-%08d; ", src_suid >> 24, source);
|
||||
freq = process_channel_to_freq (opts, state, channel);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
@@ -710,7 +730,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
|
||||
|
||||
//Skip tuning encrypted calls if enc calls are disabled -- abb formats do not carry svc bits :(
|
||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
// if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
|
||||
//unit to unit needs work, may fail under certain conditions (first blocked, second allowed, etc) (labels should still work though)
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
@@ -747,16 +767,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;
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -851,7 +871,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
if ( (svc1 & 0x40) && (svc2 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
|
||||
int loop = 1;
|
||||
if (channelt2 == channelt2) loop = 1;
|
||||
if (channelt1 == channelt2) loop = 1;
|
||||
else loop = 2;
|
||||
//assigned inside loop
|
||||
long int tunable_freq = 0;
|
||||
@@ -917,16 +937,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -996,41 +1016,52 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
freq1 = process_channel_to_freq (opts, state, channel1);
|
||||
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
if (so2 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so2 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
if (channel2 != channel1 && channel2 != 0 && channel2 != 0xFFFF)
|
||||
{
|
||||
if (so2 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so2 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so2 & 0x7); //call priority
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
if (so2 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so2 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (so2 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so2 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so2 & 0x7); //call priority
|
||||
}
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
}
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
if (so3 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so3 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
if (channel3 != channel2 && channel3 != 0 && channel3 != 0xFFFF)
|
||||
{
|
||||
if (so3 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so3 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so3 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so3 & 0x7); //call priority
|
||||
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
|
||||
if (so3 & 0x80) fprintf (stderr, " Emergency");
|
||||
if (so3 & 0x40) fprintf (stderr, " Encrypted");
|
||||
if (opts->payload == 1) //hide behind payload due to len
|
||||
{
|
||||
if (so3 & 0x20) fprintf (stderr, " Duplex");
|
||||
if (so3 & 0x10) fprintf (stderr, " Packet");
|
||||
else fprintf (stderr, " Circuit");
|
||||
if (so3 & 0x8) fprintf (stderr, " R"); //reserved bit is on
|
||||
fprintf (stderr, " Priority %d", so3 & 0x7); //call priority
|
||||
}
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
}
|
||||
freq3 = process_channel_to_freq (opts, state, channel3);
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2, channel3, group3);
|
||||
|
||||
//add active channel to string for ncurses display (multi check)
|
||||
// if (channel3 != channel2 && channel2 != channel1 && channel3 != 0 && channel3 != 0xFFFF)
|
||||
// sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2, channel3, group3);
|
||||
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//Skip tuning encrypted calls if enc calls are disabled
|
||||
if ( (so1 & 0x40) && (so2 & 0x40) && (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
|
||||
if ( (so1 & 0x40) && (so2 & 0x40) && (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //this?
|
||||
|
||||
int loop = 3;
|
||||
|
||||
@@ -1108,16 +1139,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1173,18 +1204,23 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
fprintf (stderr, "\n Group Voice Channel Grant Update - Implicit");
|
||||
fprintf (stderr, "\n Channel 1 [%04X] Group 1 [%d][%04X]", channel1, group1, group1);
|
||||
freq1 = process_channel_to_freq (opts, state, channel1);
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
if (channel2 != channel1 && channel2 != 0 && channel2 != 0xFFFF)
|
||||
{
|
||||
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
|
||||
freq2 = process_channel_to_freq (opts, state, channel2);
|
||||
}
|
||||
|
||||
//add active channel to string for ncurses display
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2);
|
||||
if (channel2 != channel1 && channel2 != 0 && channel2 != 0xFFFF)
|
||||
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2);
|
||||
else sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel1, group1);
|
||||
state->last_active_time = time(NULL);
|
||||
|
||||
//Skip tuning group calls if group calls are disabled
|
||||
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
|
||||
|
||||
//Skip tuning encrypted calls if enc calls are disabled -- abb formats do not carry svc bits :(
|
||||
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
// if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
|
||||
|
||||
int loop = 1;
|
||||
if (channel1 == channel2) loop = 1;
|
||||
@@ -1244,16 +1280,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;
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1373,16 +1409,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;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -1804,6 +1840,38 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
}
|
||||
|
||||
//Tait Observed "tdma slot counter", this can be a single message in a facch idle, or a ndary message in a sacch channel update
|
||||
if (MAC[len_a+1] == 0xB5 && MAC[len_a+2] == 0xD8)
|
||||
{
|
||||
uint8_t mfid = MAC[len_a+2];
|
||||
uint16_t sc = (MAC[len_a+4] << 8) + MAC[len_a+5]; //its possible that not all bits in these two bytes are slots, similar to time_date_ann
|
||||
uint8_t len = MAC[len_a+3]; //5 on this opcode (including opcode, mfid, len, and two bytes for slot count)
|
||||
|
||||
//if using the same slot counter bits as time_date_ann,
|
||||
//then we can trunc the slot count to 13 bits
|
||||
// sc &= 0x1FFF;
|
||||
|
||||
fprintf (stderr, "\n MFID %02X (Tait); Len: %d; Opcode: %02X; Slot Counter: %04X;", mfid, len, MAC[len_a+1], sc);
|
||||
|
||||
len_b = 5;
|
||||
|
||||
}
|
||||
|
||||
//look for other unknown Tait opcodes
|
||||
if (MAC[len_a+1] != 0xB5 && MAC[len_a+2] == 0xD8)
|
||||
{
|
||||
uint8_t mfid = MAC[len_a+2];
|
||||
uint8_t len = MAC[len_a+3];
|
||||
fprintf (stderr, "\n MFID %02X (Tait); Len: %d; Opcode: %02X;", mfid, len, MAC[len_a+1]);
|
||||
|
||||
//dump entire payload
|
||||
fprintf (stderr, " Payload: ");
|
||||
for (i = 4; i < 24; i++)
|
||||
fprintf (stderr, "%02llX", MAC[i+len_a]);
|
||||
|
||||
len_b = len;
|
||||
}
|
||||
|
||||
/*
|
||||
Maybe this is why some of these SYNC_BCST PDUs have zeroes in most fields
|
||||
|
||||
@@ -2221,15 +2289,15 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
if (MAC[1+len_a] == 0x21)
|
||||
{
|
||||
src_suid = (MAC[8+len_a] << 48) | (MAC[9+len_a] << 40) | (MAC[10+len_a] << 32) | (MAC[11+len_a] << 24) |
|
||||
(MAC[12+len_a] << 16) | (MAC[13+len_a] << 8) | (MAC[14+len_a] << 0);
|
||||
src_suid = (MAC[8+len_a] << 48ULL) | (MAC[9+len_a] << 40ULL) | (MAC[10+len_a] << 32ULL) | (MAC[11+len_a] << 24ULL) |
|
||||
(MAC[12+len_a] << 16ULL) | (MAC[13+len_a] << 8ULL) | (MAC[14+len_a] << 0ULL);
|
||||
|
||||
src = src_suid & 0xFFFFFF; //last 24 of completed SUID?
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n VCH %d - TG: %d; SRC: %d; ", slot, gr, src);
|
||||
|
||||
if (MAC[1+len_a] == 0x21) fprintf (stderr, "SUID: %lld; ", src_suid);
|
||||
if (MAC[1+len_a] == 0x21) fprintf (stderr, "SUID: %08llX-%08d; ", src_suid >> 24, src);
|
||||
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
@@ -2265,14 +2333,25 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
}
|
||||
}
|
||||
|
||||
//1 or 21, group voice channel message, abb and ext
|
||||
//1 or 21, unit to unit voice channel message, abb and ext
|
||||
if (MAC[1+len_a] == 0x2 || MAC[1+len_a] == 0x22)
|
||||
{
|
||||
int svc = MAC[2+len_a];
|
||||
int gr = (MAC[3+len_a] << 16) | (MAC[4+len_a] << 8) | MAC[5+len_a];
|
||||
int src = (MAC[6+len_a] << 16) | (MAC[7+len_a] << 8) | MAC[8+len_a];
|
||||
unsigned long long int src_suid = 0;
|
||||
|
||||
fprintf (stderr, "\n VCH %d - TG %d SRC %d ", slot, gr, src);
|
||||
if (MAC[1+len_a] == 0x21)
|
||||
{
|
||||
src_suid = (MAC[9+len_a] << 48ULL) | (MAC[10+len_a] << 40ULL) | (MAC[11+len_a] << 32ULL) | (MAC[12+len_a] << 24ULL) |
|
||||
(MAC[13+len_a] << 16ULL) | (MAC[14+len_a] << 8ULL) | (MAC[15+len_a] << 0ULL);
|
||||
|
||||
src = src_suid & 0xFFFFFF;
|
||||
}
|
||||
|
||||
fprintf (stderr, "\n VCH %d - TGT: %d; SRC %d; ", slot, gr, src);
|
||||
|
||||
if (MAC[1+len_a] == 0x22) fprintf (stderr, "SUID: %08llX-%08d; ", src_suid >> 24, src);
|
||||
|
||||
if (svc & 0x80) fprintf (stderr, " Emergency");
|
||||
if (svc & 0x40) fprintf (stderr, " Encrypted");
|
||||
|
||||
@@ -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;
|
||||
@@ -370,6 +374,20 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
process_MAC_VPDU(opts, state, 1, SMAC);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
||||
// {
|
||||
// if (state->currentslot == 1)
|
||||
// {
|
||||
// opts->slot1_on = 0;
|
||||
// opts->slot2_on = 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
//blank the call string here -- slot variable is already flipped accordingly for sacch
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
@@ -498,6 +516,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 +557,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 +614,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 +643,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 +745,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 +756,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;
|
||||
|
||||
@@ -742,6 +766,20 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
process_MAC_VPDU(opts, state, 0, FMAC);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
// if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
|
||||
// {
|
||||
// if (state->currentslot == 0)
|
||||
// {
|
||||
// opts->slot1_on = 0;
|
||||
// opts->slot2_on = 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// opts->slot1_on = 1;
|
||||
// opts->slot2_on = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
//blank the call string here
|
||||
sprintf (state->call_string[slot], "%s", " "); //21 spaces
|
||||
|
||||
|
||||
139
src/provoice.c
139
src/provoice.c
@@ -6,6 +6,7 @@
|
||||
void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, dibit;
|
||||
uint16_t k = 0;
|
||||
char imbe7100_fr1[7][24];
|
||||
char imbe7100_fr2[7][24];
|
||||
const int *w, *x;
|
||||
@@ -21,18 +22,23 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
uint16_t lid = 0; //lid value 16-bit
|
||||
unsigned long long int secondary = 0; //secondary 64-bits after lid, before voice
|
||||
|
||||
uint8_t spacer_bit[8]; //check this value to see if its a status thing (like P25 P1)
|
||||
memset (spacer_bit, 0, sizeof (spacer_bit));
|
||||
uint16_t bf = 0; //the 16-bit value in-between imbe 2 and imbe 3 that is usually 2175
|
||||
|
||||
fprintf (stderr," VOICE");
|
||||
|
||||
//print group and source values if EA trunked
|
||||
//print group/target and source values if EA trunked
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->ea_mode == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KGRN);
|
||||
fprintf (stderr, " Site: %lld Group: %d Source: %d LCN: %d ",
|
||||
state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
|
||||
if (state->lasttg > 100000) {
|
||||
// I-Call
|
||||
fprintf (stderr, " Site: %lld Target: %d Source: %d LCN: %d ",
|
||||
state->edacs_site_id, state->lasttg - 100000, state->lastsrc, state->edacs_tuned_lcn);
|
||||
} else {
|
||||
// Group call
|
||||
fprintf (stderr, " Site: %lld Group: %d Source: %d LCN: %d ",
|
||||
state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//print afs value if standard/networked trunked
|
||||
@@ -46,7 +52,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
//load all initial bits before voice into raw_bits array for analysis/handling
|
||||
for (i = 0; i < 64+16+64; i++)
|
||||
raw_bits[i] = getDibit (opts, state);
|
||||
raw_bits[k++] = getDibit (opts, state);
|
||||
|
||||
//Note: the initial 144-bits seem to be provisioned differently depending on system type
|
||||
initial = (unsigned long long int)ConvertBitIntoBytes(&raw_bits[0], 64);
|
||||
@@ -71,7 +77,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[144+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
@@ -82,7 +88,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[150+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,7 +99,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+282] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
@@ -104,17 +110,15 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+288] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[0] = dibit;
|
||||
raw_bits[292] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[1] = dibit;
|
||||
raw_bits[293] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
// imbe frames 1,2 second half
|
||||
for (j = 0; j < 2; j++)
|
||||
@@ -123,7 +127,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+294] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
@@ -134,7 +138,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[296+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
@@ -144,7 +148,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[302+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +158,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+338] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 5;
|
||||
@@ -165,7 +169,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+343] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
@@ -176,7 +180,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[348+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
@@ -187,7 +191,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[354+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -198,7 +202,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+438] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
@@ -209,36 +213,31 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+443] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
if (opts->floating_point == 0)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
if (opts->floating_point == 0)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[2] = dibit;
|
||||
raw_bits[448] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[3] = dibit;
|
||||
raw_bits[449] = dibit;
|
||||
|
||||
//resume raw_bits at +6 current value to round out payload bytes
|
||||
//easier to visualize patterns
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
raw_bits[i+450+6] = getDibit (opts, state);
|
||||
raw_bits[k++] = getDibit (opts, state);
|
||||
|
||||
bf = (uint16_t)ConvertBitIntoBytes(&raw_bits[456], 16);
|
||||
bf = (uint16_t)ConvertBitIntoBytes(&raw_bits[54*8], 16);
|
||||
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n BF: %04X ", bf);
|
||||
@@ -254,7 +253,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+466+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
@@ -265,7 +264,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+472+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +274,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+604+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 6;
|
||||
@@ -286,17 +285,15 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[i+610+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[4];
|
||||
raw_bits[614+2] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[5];
|
||||
raw_bits[615+2] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
// imbe frames 3,4 second half
|
||||
for (j = 0; j < 2; j++)
|
||||
@@ -305,7 +302,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+616+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
@@ -315,7 +312,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+618+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
@@ -325,7 +322,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+624+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +332,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+660+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
@@ -345,7 +342,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+665+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
@@ -356,7 +353,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+670+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
@@ -366,7 +363,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[6+676+j+(i*12)] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +373,7 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+760+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
w -= 5;
|
||||
@@ -387,56 +384,48 @@ void processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
raw_bits[j+765+6] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
if (opts->floating_point == 0)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
if (opts->floating_point == 0)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
if (opts->floating_point == 1)
|
||||
playSynthesizedVoiceFM(opts, state);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[6] = dibit;
|
||||
raw_bits[782] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
spacer_bit[7] = dibit;
|
||||
raw_bits[783] = dibit;
|
||||
raw_bits[k++] = dibit;
|
||||
|
||||
#ifdef PVDEBUG
|
||||
|
||||
spacer = (uint8_t)ConvertBitIntoBytes(&spacer_bit[0], 8);
|
||||
//payload on all raw bytes for analysis
|
||||
if (opts->payload == 1)
|
||||
fprintf (stderr, "\n SP: %X", spacer);
|
||||
|
||||
//convert raw bits into raw bytes for payload analysis
|
||||
for (j = 0; j < 98; j++)
|
||||
// if (opcode != 0x3333) //EA Voice
|
||||
{
|
||||
raw_bytes[j] = (uint8_t)ConvertBitIntoBytes(&raw_bits[(j*8)], 8);
|
||||
}
|
||||
|
||||
//payload on all raw bytes for analysis...its a lot of 'em
|
||||
if (opts->payload == 1) //find better thingy later or change this
|
||||
// if (opcode != 0x3333)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "\n pV Payload Dump: \n ");
|
||||
for (j = 0; j < 98; j++)
|
||||
for (i = 0; i < k/8; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", raw_bytes[j]);
|
||||
if (j == 17 || j == 35 || j == 53 || j == 71 || j == 89)
|
||||
{
|
||||
|
||||
// if ( (i != 0) && ((i%26) == 0) )
|
||||
// fprintf (stderr, "\n ");
|
||||
|
||||
uint16_t top = (uint16_t)ConvertBitIntoBytes(raw_bits+(i*8), 16);
|
||||
if (top == 0x0EBF && i != 0)
|
||||
fprintf (stderr, "\n ");
|
||||
}
|
||||
|
||||
raw_bytes[i] = (uint8_t)ConvertBitIntoBytes(raw_bits+(i*8), 8);
|
||||
fprintf (stderr, "%02X", raw_bytes[i]);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
248
src/pulse_devices.c
Normal file
248
src/pulse_devices.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* pulse_devices.c
|
||||
* DSD-FME - Pulse Audio Sink and Source Enumeration
|
||||
*
|
||||
* based on gist found here
|
||||
* https://gist.github.com/andrewrk/6470f3786d05999fcb48
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2024-05 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
// This callback gets called when our context changes state. We really only
|
||||
// care about when it's ready or if it has failed
|
||||
void pa_state_cb(pa_context *c, void *userdata)
|
||||
{
|
||||
pa_context_state_t state;
|
||||
int *pa_ready = userdata;
|
||||
|
||||
state = pa_context_get_state(c);
|
||||
switch (state)
|
||||
{
|
||||
// There are just here for reference
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
default:
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
*pa_ready = 2;
|
||||
break;
|
||||
case PA_CONTEXT_READY:
|
||||
*pa_ready = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pa_mainloop will call this function when it's ready to tell us about a sink.
|
||||
// Since we're not threading, there's no need for mutexes on the devicelist
|
||||
// structure
|
||||
void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata)
|
||||
{
|
||||
pa_devicelist_t *pa_devicelist = userdata;
|
||||
int ctr = 0;
|
||||
|
||||
UNUSED(c);
|
||||
|
||||
// If eol is set to a positive number, you're at the end of the list
|
||||
if (eol > 0)
|
||||
return;
|
||||
|
||||
// We know we've allocated 16 slots to hold devices. Loop through our
|
||||
// structure and find the first one that's "uninitialized." Copy the
|
||||
// contents into it and we're done. If we receive more than 16 devices,
|
||||
// they're going to get dropped. You could make this dynamically allocate
|
||||
// space for the device list, but this is a simple example.
|
||||
|
||||
for (ctr = 0; ctr < 16; ctr++)
|
||||
{
|
||||
if (! pa_devicelist[ctr].initialized)
|
||||
{
|
||||
strncpy(pa_devicelist[ctr].name, l->name, 511);
|
||||
strncpy(pa_devicelist[ctr].description, l->description, 255);
|
||||
pa_devicelist[ctr].index = l->index;
|
||||
pa_devicelist[ctr].initialized = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See above. This callback is pretty much identical to the previous
|
||||
void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata)
|
||||
{
|
||||
pa_devicelist_t *pa_devicelist = userdata;
|
||||
int ctr = 0;
|
||||
|
||||
UNUSED(c);
|
||||
|
||||
if (eol > 0)
|
||||
return;
|
||||
|
||||
for (ctr = 0; ctr < 16; ctr++)
|
||||
{
|
||||
if (! pa_devicelist[ctr].initialized)
|
||||
{
|
||||
strncpy(pa_devicelist[ctr].name, l->name, 511);
|
||||
strncpy(pa_devicelist[ctr].description, l->description, 255);
|
||||
pa_devicelist[ctr].index = l->index;
|
||||
pa_devicelist[ctr].initialized = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pa_get_devicelist(pa_devicelist_t *input, pa_devicelist_t *output)
|
||||
{
|
||||
// Define our pulse audio loop and connection variables
|
||||
pa_mainloop *pa_ml;
|
||||
pa_mainloop_api *pa_mlapi;
|
||||
pa_operation *pa_op;
|
||||
pa_context *pa_ctx;
|
||||
|
||||
|
||||
// We'll need these state variables to keep track of our requests
|
||||
int state = 0;
|
||||
int pa_ready = 0;
|
||||
|
||||
// Initialize our device lists
|
||||
memset(input, 0, sizeof(pa_devicelist_t) * 16);
|
||||
memset(output, 0, sizeof(pa_devicelist_t) * 16);
|
||||
|
||||
// Create a mainloop API and connection to the default server
|
||||
pa_ml = pa_mainloop_new();
|
||||
pa_mlapi = pa_mainloop_get_api(pa_ml);
|
||||
pa_ctx = pa_context_new(pa_mlapi, "test");
|
||||
|
||||
// This function connects to the pulse server
|
||||
pa_context_connect(pa_ctx, NULL, 0, NULL);
|
||||
|
||||
|
||||
// This function defines a callback so the server will tell us it's state.
|
||||
// Our callback will wait for the state to be ready. The callback will
|
||||
// modify the variable to 1 so we know when we have a connection and it's
|
||||
// ready.
|
||||
// If there's an error, the callback will set pa_ready to 2
|
||||
pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
|
||||
|
||||
// Now we'll enter into an infinite loop until we get the data we receive
|
||||
// or if there's an error
|
||||
for (;;)
|
||||
{
|
||||
// We can't do anything until PA is ready, so just iterate the mainloop
|
||||
// and continue
|
||||
if (pa_ready == 0)
|
||||
{
|
||||
pa_mainloop_iterate(pa_ml, 1, NULL);
|
||||
continue;
|
||||
}
|
||||
// We couldn't get a connection to the server, so exit out
|
||||
if (pa_ready == 2)
|
||||
{
|
||||
pa_context_disconnect(pa_ctx);
|
||||
pa_context_unref(pa_ctx);
|
||||
pa_mainloop_free(pa_ml);
|
||||
return -1;
|
||||
}
|
||||
// At this point, we're connected to the server and ready to make
|
||||
// requests
|
||||
switch (state)
|
||||
{
|
||||
// State 0: we haven't done anything yet
|
||||
case 0:
|
||||
// This sends an operation to the server. pa_sinklist_info is
|
||||
// our callback function and a pointer to our devicelist will
|
||||
// be passed to the callback The operation ID is stored in the
|
||||
// pa_op variable
|
||||
pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, output);
|
||||
|
||||
// Update state for next iteration through the loop
|
||||
state++;
|
||||
break;
|
||||
case 1:
|
||||
// Now we wait for our operation to complete. When it's
|
||||
// complete our pa_output_devicelist is filled out, and we move
|
||||
// along to the next state
|
||||
if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
|
||||
{
|
||||
pa_operation_unref(pa_op);
|
||||
|
||||
// Now we perform another operation to get the source
|
||||
// (input device) list just like before. This time we pass
|
||||
// a pointer to our input structure
|
||||
pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, input);
|
||||
// Update the state so we know what to do next
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
|
||||
{
|
||||
// Now we're done, clean up and disconnect and return
|
||||
pa_operation_unref(pa_op);
|
||||
pa_context_disconnect(pa_ctx);
|
||||
pa_context_unref(pa_ctx);
|
||||
pa_mainloop_free(pa_ml);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// We should never see this state
|
||||
fprintf(stderr, "in state %d\n", state);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Iterate the main loop and go again. The second argument is whether
|
||||
// or not the iteration should block until something is ready to be
|
||||
// done. Set it to zero for non-blocking.
|
||||
pa_mainloop_iterate(pa_ml, 1, NULL);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int pulse_list()
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
int ctr;
|
||||
|
||||
// This is where we'll store the input device list
|
||||
pa_devicelist_t pa_input_devicelist[16];
|
||||
|
||||
// This is where we'll store the output device list
|
||||
pa_devicelist_t pa_output_devicelist[16];
|
||||
|
||||
if (pa_get_devicelist(pa_input_devicelist, pa_output_devicelist) < 0)
|
||||
{
|
||||
fprintf(stderr, "failed to get device list\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (ctr = 0; ctr < 16; ctr++)
|
||||
{
|
||||
if (! pa_output_devicelist[ctr].initialized)
|
||||
break;
|
||||
|
||||
printf("=======[ Output Device #%d ]=======\n", ctr+1);
|
||||
printf("Description: %s\n", pa_output_devicelist[ctr].description);
|
||||
printf("Name: %s\n", pa_output_devicelist[ctr].name);
|
||||
printf("Index: %d\n", pa_output_devicelist[ctr].index);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (ctr = 0; ctr < 16; ctr++)
|
||||
{
|
||||
if (! pa_input_devicelist[ctr].initialized)
|
||||
break;
|
||||
|
||||
printf("=======[ Input Device #%d ]=======\n", ctr+1);
|
||||
printf("Description: %s\n", pa_input_devicelist[ctr].description);
|
||||
printf("Name: %s\n", pa_input_devicelist[ctr].name);
|
||||
printf("Index: %d\n", pa_input_devicelist[ctr].index);
|
||||
printf("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -815,6 +815,34 @@ void dongle_init(struct dongle_state *s)
|
||||
s->demod_target = &demod;
|
||||
}
|
||||
|
||||
void demod_init_analog(struct demod_state *s)
|
||||
{
|
||||
s->rate_in = rtl_bandwidth;
|
||||
s->rate_out = rtl_bandwidth;
|
||||
s->squelch_level = 0;
|
||||
s->conseq_squelch = 10;
|
||||
s->terminate_on_squelch = 0;
|
||||
s->squelch_hits = 11;
|
||||
s->downsample_passes = 1; //
|
||||
s->comp_fir_size = 0;
|
||||
s->prev_index = 0;
|
||||
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
|
||||
s->custom_atan = 0;
|
||||
s->deemph = 1; //
|
||||
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
|
||||
s->mode_demod = &fm_demod;
|
||||
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
|
||||
s->prev_lpr_index = 0;
|
||||
s->deemph_a = 0; //
|
||||
s->now_lpr = 0;
|
||||
s->dc_block = 1; //
|
||||
s->dc_avg = 0;
|
||||
pthread_rwlock_init(&s->rw, NULL);
|
||||
pthread_cond_init(&s->ready, NULL);
|
||||
pthread_mutex_init(&s->ready_m, NULL);
|
||||
s->output_target = &output;
|
||||
}
|
||||
|
||||
void demod_init_ro2(struct demod_state *s)
|
||||
{
|
||||
s->rate_in = rtl_bandwidth;
|
||||
@@ -999,12 +1027,15 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
int r;
|
||||
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
|
||||
|
||||
//this needs to be initted first, then we set the parameters
|
||||
dongle_init(&dongle);
|
||||
//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)
|
||||
demod_init_analog(&demod);
|
||||
else demod_init(&demod);
|
||||
output_init(&output);
|
||||
controller_init(&controller);
|
||||
@@ -1027,9 +1058,7 @@ void open_rtlsdr_stream(dsd_opts *opts)
|
||||
if (opts->rtl_udp_port != 0) port = opts->rtl_udp_port; //set this here, only open socket thread if set
|
||||
if (opts->rtl_gain_value > 0) {
|
||||
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm works
|
||||
}
|
||||
volume_multiplier = opts->rtl_volume_multiplier;
|
||||
// fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
|
||||
}
|
||||
|
||||
/* quadruple sample_rate to limit to Δθ to ±π/2 */
|
||||
demod.rate_in *= demod.post_downsample;
|
||||
|
||||
12
src/ysf.c
12
src/ysf.c
@@ -697,7 +697,7 @@ void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start,
|
||||
state->synctype = 28;
|
||||
|
||||
uint8_t b1, b2;
|
||||
for (start; start < stop; start++)
|
||||
for (; start < stop; start++)
|
||||
{
|
||||
w = YnW;
|
||||
x = YnX;
|
||||
@@ -737,7 +737,7 @@ void ysf_ehr (dsd_opts * opts, dsd_state * state, uint8_t dbuf[180], int start,
|
||||
writeSynthesizedVoice (opts, state);
|
||||
|
||||
if (opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
|
||||
if(opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
@@ -1027,7 +1027,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
||||
if (opts->wav_out_f != NULL)
|
||||
writeSynthesizedVoice (opts, state);
|
||||
if (opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
|
||||
if(opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
@@ -1083,7 +1083,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
||||
vstop = 5;
|
||||
}
|
||||
|
||||
for (dstart; dstart < dstop; dstart++)
|
||||
for (; dstart < dstop; dstart++)
|
||||
{
|
||||
//get dibits for CSD3 Sub Header DCH -- still need samples to test this with
|
||||
for (j = 0; j < 36; j++) //dbufFR[2][190]
|
||||
@@ -1094,7 +1094,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
for (vstart; vstart < vstop; vstart++)
|
||||
for (; vstart < vstop; vstart++)
|
||||
{
|
||||
|
||||
//init a bunch of stuff
|
||||
@@ -1147,7 +1147,7 @@ void processYSF(dsd_opts * opts, dsd_state * state)
|
||||
writeSynthesizedVoice (opts, state);
|
||||
|
||||
if (opts->pulse_digi_out_channels == 1)
|
||||
playSynthesizedVoice(opts, state);
|
||||
playSynthesizedVoiceMS(opts, state);
|
||||
|
||||
if(opts->pulse_digi_out_channels == 2)
|
||||
playSynthesizedVoiceSS(opts, state);
|
||||
|
||||
Reference in New Issue
Block a user