283 Commits
2024 ... 2025

Author SHA1 Message Date
lwvmobile
5ad9f4107c P25: Add Tait (mfid: D8) Slot Count vPDU (op: B5); 2025-01-26 13:31:54 -05:00
lwvmobile
bc140ec081 Add ES Aux Header to r12 MPDU; Fix Format Security Warning on Debug UTF16 Prints; 2024-12-13 23:39:21 -05:00
lwvmobile
d904289060 Fix Several P25p1 LCW regardless of MFID presence; 2024-12-13 23:21:34 -05:00
lwvmobile
e13bd4f323 More P25p1 MPDU Payload Fixes; 2024-12-13 15:40:48 -05:00
lwvmobile
5752f1b84a Fix P25p1 Confirmed Data Payload Output; 2024-12-13 15:31:24 -05:00
lwvmobile
5e516ed6d1 Fix P25p1 ADJSS BCST LCW; 2024-12-13 12:35:54 -05:00
lwvmobile
2ceeeb82af Add Text Debug PDU Code for P25 and DMR PDUs; 2024-12-12 05:18:33 -05:00
lwvmobile
2883e44a9d Fix P25p1 SCC BCST LCW; 2024-12-10 14:06:12 -05:00
lwvmobile
20747db2cc Fix DSP output for DMR SB/RC;
Fix DSP output order on BS voice loop;
RC PDU Format Line Break;
Debug RC data testing on BS VC-F;
2024-12-08 16:55:33 -05:00
lwvmobile
c2f22ac399 Add Some More P25p1 PDU SAPs;
Add P25p1 PDU Aux ES Info;

Fix Misc Formatting and Cleanup on P25p1 PDU Blocks;
2024-12-07 14:40:45 -05:00
lwvmobile
b8beede921 Remove Unused Bits of Code for DMR/RS Sync Pattern (Fixes Bug if RES Sync is detected and flag tripped); #270 2024-11-17 08:43:11 -05:00
lwvmobile
cd32158a73 Fix len on unpack_ambe function; 2024-11-13 15:11:51 -05:00
lwvmobile
a8ec6dbe37 Add Frame Number to dPMR with Payload Verbosity; 2024-11-11 14:45:18 -05:00
lwvmobile
f22af7c5fc Fix Mono to Stereo Interleave Audio Gain on YSF/DMR MS; 2024-10-24 00:24:34 -04:00
lwvmobile
a4b53f88a1 Disable PV Debug Output; 2024-10-23 23:31:17 -04:00
lwvmobile
4567e2f4a4 DMR: Con+ Call/Slot Termination; 2024-10-23 23:21:00 -04:00
lwvmobile
8a3fd87784 PV: Remove Spacer Bits; Misc Cleanup; 2024-10-23 22:41:33 -04:00
lwvmobile
c428ce32b2 Merge branch 'pv_diag' into aw_dev_merge 2024-10-23 22:34:24 -04:00
lwvmobile
2ae9c50d47 Merge pull request #269 from volo-zyko/fix-compiler-warnings
Fix some compiler warnings and add corresponding compiler flags
2024-08-30 11:12:23 -04:00
Volo Zyko
dfcc8d513d Fix some compiler warnings and add corresponding compiler flags 2024-08-29 15:05:52 +03:00
lwvmobile
7c9d032c99 PVDebug Testing; 2024-07-21 10:08:39 -04:00
lwvmobile
f6fc91a051 Include pack_ambe and unpack_ambe functions and use during certain keystream applications; 2024-07-20 16:41:35 -04:00
lwvmobile
8b76daa35f Fix/Simplify AMBE and IMBE Print Code; Include Bit/Byte Utility Functions; 2024-07-20 16:41:07 -04:00
lwvmobile
8b883f556f M17: Packet Decode Fix Sanity Check So It Doesn't Break CRC; 2024-06-15 01:18:47 -04:00
lwvmobile
beefaae0fa M17: Disable Debug Print on PKT Assembly; 2024-06-15 00:56:31 -04:00
lwvmobile
13e778b123 M17: Fix Potential Core Dump (overflow) on Packet Assembly on Bad Packet Decode; 2024-06-15 00:47:16 -04:00
lwvmobile
7f7c13a72a M17: Don't Attempt To Decode Encrypted Packet Data; Disable Annoying Nonce TS Warning; 2024-06-15 00:21:20 -04:00
lwvmobile
f2312e63eb M17: Disable Duplicate (Debug) LSF and Change Default DST Value;
M17: Fix Examples in Usage;

M17: Disable Nonce/IV Warning;

M17: Add Support For OTAKD Recognition (skip decode);
2024-06-13 16:21:25 -04:00
lwvmobile
d6adaa87c7 M17: Fix Meta Text Decoding to skip control byte on string, but display len/seg number; LSF Payload CRC Line Break Nit; 2024-06-13 15:36:14 -04:00
lwvmobile
20e35a00ba M17: Adjustments to PKT Data CRC; 2024-06-10 04:36:55 -04:00
lwvmobile
8610ee8956 M17: Fix Bugs With SRC/DST Values in Meta Extended CSD; 2024-06-09 05:47:04 -04:00
lwvmobile
92fbdabbe5 M17: Tweaks to Meta Decode Conditions; 2024-06-08 13:45:18 -04:00
lwvmobile
25659ba920 M17: Tweak Output on GNSS Position Data; 2024-06-08 03:07:35 -04:00
lwvmobile
b2ce60b843 Update Install Notes to Mention Debian 12; 2024-06-07 22:22:42 -04:00
lwvmobile
c87ad08371 M17: Fix META Decode when not IV and Decode META Text as UTF-8 and Not RAW; 2024-06-07 22:20:36 -04:00
lwvmobile
94688fddd4 Change Download For Ubuntu 24.04 Script from aw_dev to audio_work branch; 2024-06-06 15:17:57 -04:00
lwvmobile
e29eba9943 Fix Error in Manual Install Packages For Ubuntu; 2024-06-06 15:15:10 -04:00
lwvmobile
920dce96fe Add Auto Installer Script For Ubuntu 24.04 LTS; #262 2024-06-05 04:23:27 -04:00
lwvmobile
e2747525a6 Patch: Remove Outdated G Patch (Again); 2024-05-31 03:44:27 -04:00
lwvmobile
a5989486ae Patch: Fix g_dmr patch to work properly with new call string and append .wav properly in Linux; 2024-05-31 01:58:38 -04:00
lwvmobile
9c58273832 DMR: Fix Per Call String on DMR Tier 3 When Trunking; 2024-05-31 01:04:39 -04:00
lwvmobile
9a9fa0c182 Patch: Delete Older Version of G Patch; Add Cretu DMR no idle print patch; 2024-05-27 20:12:28 -04:00
lwvmobile
319d0b9866 OSS: Quick Bugfix for hpf_d when TDMA slot 1/2 volume issues; Updated g_dmr patch; 2024-05-27 20:02:48 -04:00
lwvmobile
5dbccaadf6 Add Per Call String For NXDN Conventional / Type-D; 2024-05-21 09:42:46 -04:00
lwvmobile
28a6777d83 DMR: Tweak to Call String Options for Display and Per Call; #258 2024-05-21 09:06:22 -04:00
lwvmobile
21afa4ba97 Add Call String To Per Call Files (group/private/emergency/enc); WIP; #258 2024-05-21 01:49:23 -04:00
lwvmobile
d60dfa7ff3 Update Usage to reflect changes to the -7 directory option; 2024-05-19 18:03:37 -04:00
lwvmobile
5d3b2ec56f Fix Some Absolute Directory Path Issues(WIP); #261 2024-05-19 16:32:27 -04:00
lwvmobile
2c55a9caab Ncurses: Device Display Spacing Nit; 2024-05-19 15:32:32 -04:00
lwvmobile
6daedf198f Update Docs: Add Audio Plumbing Information; 2024-05-19 06:26:09 -04:00
lwvmobile
8d52ce2ac9 Add Pulse Input / Output Sink / Source Name to Ncurses Terminal; 2024-05-19 05:59:10 -04:00
lwvmobile
63e484cc91 Optional User Input Argument for Pulse Audio Sink / Source Use; 2024-05-19 05:34:56 -04:00
lwvmobile
e3ecace5db Pulse Audio Sink and Source Enumeration WIP; 2024-05-19 04:59:26 -04:00
lwvmobile
f9add0b997 M17: Misc Fixes and Tweaks; 2024-05-10 12:33:39 -04:00
lwvmobile
d3c942d475 Phase 1 Non-standard IMBE Log Tweaking and Notes; 2024-05-10 12:32:42 -04:00
lwvmobile
3d1e28fb3a Fix Error Handling and Error String on Pulse Input and Output Opening #259 2024-05-10 12:08:38 -04:00
lwvmobile
c07fa3a0bc Cast &err into pa_simple_new on ALL calls to the function (missed a few in haste); 2024-05-08 09:33:38 -04:00
lwvmobile
ef94b311fa Add Error Handling and Error String on Pulse Input and Output Opening #259 ; Change Input 'Name' on M17 Voice Input so it doesn't default to same source as RF Signal Input; 2024-05-06 21:46:29 -04:00
lwvmobile
79d5b795e3 Merge pull request #257 from ilyacodes/aw-dev/standard-test
EDACS: Correctly identify test calls on standard
2024-04-27 11:08:13 -04:00
ilyacodes
d0c20be7f3 EDACS: Correctly identify test calls on standard 2024-04-27 09:54:59 -04:00
lwvmobile
6833275960 Merge pull request #256 from lwvmobile/aw_dev_timefix
Consolidate and Fix Time and Date Functions #255
2024-04-26 21:47:47 -04:00
lwvmobile
601a1ad2d1 TIME: Fix printFrameSync Oopsie; NULL PTR on Debug symbolfile; 2024-04-25 21:23:20 -04:00
lwvmobile
db036f4dfc TIME: Set Allocated Pointers to NULL after free()'d; 2024-04-25 18:22:28 -04:00
lwvmobile
7bcd29abec NCURSES: Move timestr/datestr around; 2024-04-25 16:15:44 -04:00
lwvmobile
c5b36af672 Add .bin loop 'debug mode' on -J; 2024-04-25 16:14:59 -04:00
lwvmobile
9da8544408 TIME: malloc and HHmmss Nits; Remove Unneeded time/date strings from Ncurses; 2024-04-25 11:27:26 -04:00
lwvmobile
ab9a9ddab3 TIME: NULL Check Before free(timestr); 2024-04-25 11:06:13 -04:00
lwvmobile
ceb695af01 NCURSES: Remove Extra Fence Post on EDACS Call History; 2024-04-25 09:24:01 -04:00
lwvmobile
1ffddf823f Fix and Consolidate Date and Time Functions (WIP); #255 2024-04-24 16:42:25 -04:00
lwvmobile
499134bc2d DMR: Reset Color Code If Not Trunking and NoCarrier; 2024-04-24 13:01:45 -04:00
lwvmobile
7a9763c6c7 DMR: Init Payload Buffer; Fix MS Data Collection; 2024-04-24 13:00:13 -04:00
lwvmobile
db7bc75739 DMR: Fix EMB_PDU CC Assignment; 2024-04-24 12:33:04 -04:00
lwvmobile
bd1dcd2a7f DMR: Set CC on MS Voice; QR Correction Limit; 2024-04-21 18:18:14 -04:00
lwvmobile
bc205cfe00 DMR: Fix Color Code Assignment, Display, and Logging; 2024-04-21 17:49:46 -04:00
lwvmobile
0f3dcf47ea Merge pull request #254 from ilyacodes/aw_dev-colour
EDACS: Fix colour for test channel updates
2024-04-21 12:43:13 -04:00
ilyacodes
3f165571d2 EDACS: Fix colour for test channel updates 2024-04-21 09:52:09 -04:00
lwvmobile
b2450b1924 Merge pull request #253 from ilyacodes/trbo-bp
DMR: Fix incorrect MotoTRBO Basic Privacy mask
2024-04-19 22:58:15 -04:00
ilyacodes
061703db7b DMR: Fix incorrect MotoTRBO Basic Privacy mask
Tested with an R7.

Basic Privacy key: `73_dec`
Encrypted silent voice: `860DD7D3F2AC80`
Mask: `7E0C7E4C7E4C00`
2024-04-19 21:01:55 -04:00
lwvmobile
50f4327306 PA: Adjust Input Fragsize / Latency;
M17: Misc Notes About UDP Audio;
2024-04-18 11:15:42 -04:00
lwvmobile
90206eac92 Patch: Add the AFD "April Fools Day" Ghost Box Gag Update as a patch to bring back around Halloween; 2024-04-16 22:43:22 -04:00
lwvmobile
f1a5d6f870 Patch: Make the Moto Type II Starter Pack a Patch so I can delete the branch for it and prevent having to do a bunch of rebase / merge conflict resolutions on between those branches later; #247 2024-04-16 22:40:00 -04:00
lwvmobile
ca506672a8 Merge pull request #251 from ilyacodes/testcall
EDACS: Test Call improvements
2024-04-16 09:00:24 -04:00
lwvmobile
3041713eb3 M17: Fix Compiler Error if librtlsdr not found / installed; 2024-04-16 06:03:05 -04:00
lwvmobile
dbc645e7b0 EDACS: Fix Unk4 Value EA Dynamic Regrouping; #252 2024-04-15 09:40:53 -04:00
lwvmobile
5d205800aa EDACS: Fix Bit Shift on EA Patch Info; Misc; #252 2024-04-15 09:30:22 -04:00
lwvmobile
e5d11c81f3 EDACS: More WIP/Tests on EA Dynamic Regrouping2; #252 2024-04-15 07:47:15 -04:00
lwvmobile
d86c520509 EDACS: More WIP/Tests on EA Dynamic Regrouping; #252 2024-04-15 07:17:07 -04:00
ilyacodes
854b421235 EDACS: fix group patch shift size 2024-04-14 11:03:50 -04:00
ilyacodes
8206a5f3f4 EDACS: print agency/fleet calls in logs 2024-04-14 10:05:09 -04:00
ilyacodes
0568475d59 EDACS: custom format for custom AFS patterns 2024-04-14 10:04:52 -04:00
ilyacodes
b5a43031f9 EDACS: rename functions to lowerCamelCase style
It's, like, mildly more consistent... and is subtly shorter, which is handy for some cases.

Though yeah we have functions with both styles in the same file.
2024-04-14 09:52:22 -04:00
ilyacodes
ba41ba57f6 EDACS: fix vc_call_type for EDACS_IS_TEST_CALL 2024-04-14 09:42:43 -04:00
ilyacodes
d84136dc92 EDACS: show agency/fleet call on channel updates too 2024-04-14 09:40:03 -04:00
ilyacodes
ad78373b43 EDACS: fix width of source for non-EA data calls 2024-04-14 09:12:26 -04:00
ilyacodes
8980207fd6 EDACS: fix wrong comment 2024-04-14 09:12:01 -04:00
ilyacodes
33d8ee70d9 EDACS: compute AFS masks using math, not copy/paste 2024-04-13 17:15:44 -04:00
ilyacodes
b86cd1bc3c EDACS: agency call and fleet call are mutually-exclusive 2024-04-13 16:52:16 -04:00
ilyacodes
57c22b484d EDACS: ugh have to pass state too 2024-04-13 16:31:27 -04:00
ilyacodes
834bd57ea6 EDACS: logging nit 2024-04-13 16:23:32 -04:00
ilyacodes
7e26b7b902 EDACS: Show agency and fleet calls based on AFS 2024-04-13 16:22:52 -04:00
lwvmobile
4eb2e770c8 EDACS: Redo Parts of EA Patch / Regroup Based on Newer Observations and Remove Overlapping Bit Range; 2024-04-13 16:19:52 -04:00
ilyacodes
0208f6240c EDACS: Fix copypasta typo in new AFS logic 2024-04-13 15:38:31 -04:00
ilyacodes
db88bfff8d EDACS: missing space 2024-04-13 14:48:32 -04:00
ilyacodes
a78b88cb90 EDACS EA: tiny log string change 2024-04-13 14:19:10 -04:00
ilyacodes
a42dd9db83 EDACS: update line telling user to specify EDACS type 2024-04-13 10:58:49 -04:00
ilyacodes
a7d7cf1c2e EDACS EA: Dynamic Regroup log consistency 2024-04-13 10:56:51 -04:00
ilyacodes
1ec8bb5c8b ncurses: trim trailing whitespace 2024-04-13 10:51:04 -04:00
ilyacodes
d8e672f796 EDACS EA: make System Dynamic Regroup KWHT so it doesn't conflict with test calls 2024-04-13 10:48:07 -04:00
ilyacodes
b577397d22 EDACS ncurses: remove extra printf argument 2024-04-13 10:44:37 -04:00
ilyacodes
832afa6c5a EDACS EA: comment 2024-04-13 10:42:26 -04:00
ilyacodes
b667d25f2a EDACS EA: cosmetic updates to I-Call/Test Call logging 2024-04-13 10:41:56 -04:00
ilyacodes
e237b5541b EDACS: Test calls should be KMAG(enta) 2024-04-13 10:40:32 -04:00
ilyacodes
bf62106953 EDACS: Differentiate test call update from individual call update on standard 2024-04-13 10:36:40 -04:00
ilyacodes
09b181449f EDACS: Differentiate test call from individual call on standard 2024-04-13 10:27:37 -04:00
ilyacodes
c073bc49c1 EDACS: Consistency for CC LCN message logging 2024-04-13 10:25:38 -04:00
ilyacodes
7b2a2031a2 EDACS: Consistency for Initiate Test Call message logging 2024-04-13 10:25:22 -04:00
ilyacodes
a90a2dadd4 EDACS: Prettier test call display 2024-04-13 10:24:10 -04:00
ilyacodes
c21aa98034 EDACS: Fix incorrect indexer for test call 2024-04-13 10:20:53 -04:00
ilyacodes
c967e1500c EDACS: Rename EDACS_IS_TESTCALL flag 2024-04-13 10:19:36 -04:00
lwvmobile
99212cc139 EDACS: Differentiate EA Test Call Assignment and Update; 2024-04-13 03:50:07 -04:00
lwvmobile
caab348a39 EDACS: Fix EA Test Call in Call History; 2024-04-13 03:21:59 -04:00
lwvmobile
f799374183 EDACS: EA Test Call Continuation (I-CALL zero); Ncurses Display of Test Call; Test Call Type; Notes; 2024-04-13 02:55:38 -04:00
lwvmobile
1f8a129137 M17: Fix Misc Cosmetic Output on IP Frame; 2024-04-13 01:39:55 -04:00
lwvmobile
ba11725087 EDACS: EA Adjacent Site Index Values and Definitions; 2024-04-12 18:01:04 -04:00
lwvmobile
79f8503c09 EDACS: Tweak EA Patch / Regroup Message; Add Comments; 2024-04-12 17:37:59 -04:00
lwvmobile
5c7f285b9d EDACS: Tweak Regroup Message Verbosity; Tweak Patch Verbosity; 2024-04-12 16:05:18 -04:00
lwvmobile
b7415e1855 EDACS: Better EA Patch Message Decoding(WIP); 2024-04-12 15:04:06 -04:00
lwvmobile
3def1f59e5 M17: Misc Output Tweaks; 2024-04-12 11:54:08 -04:00
lwvmobile
7b8a79b8ea Merge pull request #250 from ilyacodes/voting
EDACS: implement voting error-correction algorithm, add new EA commands, refactor message parsing
2024-04-12 11:52:10 -04:00
ilyacodes
9695438fcd EDACS EA: system info and site info parsing 2024-04-11 07:57:55 -04:00
ilyacodes
49cd974dcb EDACS EA: log formatting 2024-04-10 22:32:43 -04:00
ilyacodes
739d373204 Merge branch 'voting' of https://github.com/ilyacodes/dsd-fme into voting 2024-04-10 22:09:36 -04:00
ilyacodes
896cb83eb2 EDACS EA: log and file formatting 2024-04-10 22:09:35 -04:00
ilyacodes
22f1261efa EDACS EA: log and file formatting 2024-04-10 22:07:45 -04:00
ilyacodes
4648b9c8eb EDACS EA: correct log output format 2024-04-10 22:04:00 -04:00
ilyacodes
e77770f608 EDACS: trim trailing whitespace 2024-04-10 19:59:08 -04:00
ilyacodes
bfa2ae8bc4 EDACS EA: Add System Dynamic Regroup Plan Bitmap command 2024-04-10 19:58:54 -04:00
ilyacodes
9c13d21f69 EDACS EA: add Unit Disable/Enable command ("kick") 2024-04-10 19:58:42 -04:00
ilyacodes
16ce501582 EDACS EA: remove dead "kick" command code 2024-04-10 19:58:27 -04:00
ilyacodes
61617db239 EDACS: remove BCH from messages prior to parsing them 2024-04-10 19:58:11 -04:00
ilyacodes
ac74a9c80e EDACS: start using new voting (for real) 2024-04-10 19:32:31 -04:00
ilyacodes
c8812db585 EDACS: remove comparison to pre-voting BCH check logic 2024-04-10 19:22:49 -04:00
ilyacodes
95aaa8fc2e EDACS: implement voting algorithm for FR BCH checks 2024-04-10 19:22:04 -04:00
lwvmobile
deb9dbed61 M17: Fix SRC Values in IP Frame Headers and Decode them; 2024-04-10 18:47:58 -04:00
lwvmobile
0feb8dc73c M17: MPKT Decode LSF Info; Misc Output Tweaks; 2024-04-10 09:36:16 -04:00
lwvmobile
6bfbdbd9df M17: MPKT Buffer Size Fix; CRC Fix; 2024-04-10 09:17:44 -04:00
lwvmobile
2160b369bb M17: Send / Receive PKTs with IP Frame WIP; 2024-04-10 08:15:36 -04:00
lwvmobile
de91defc20 DMR Con+ Output Tweaks; Complier Warning Fix; 2024-04-09 21:39:13 -04:00
lwvmobile
3fbff95b2b Initialize RRC Input Filter Memory; Misc Work; Change input/output CLI for M17 UDP IP Frames to prevent accidental triggers on input files that are named with m17; 2024-04-09 18:45:53 -04:00
lwvmobile
6facababd7 EDACS: Move TG Hold Display; Fix TG Hold Override when I-Call; 2024-04-09 13:38:07 -04:00
lwvmobile
dc3dc80d8f M17: Tweak Ncurses Display on Encoder; 2024-04-09 12:07:23 -04:00
lwvmobile
202fbf3dbc M17: Make IP Frame UDP Input/Output Configurable via CLI -i and -o; 2024-04-09 11:43:41 -04:00
lwvmobile
f6283f4807 M17: Enable Ncurses Terminal for IP Frame; Misc; 2024-04-09 10:04:39 -04:00
lwvmobile
1f7ddbecdf M17: UDP Socket Receiver and IP Frame Tweaks; 2024-04-09 01:20:22 -04:00
lwvmobile
129af0ba9e M17: Misc Handling / Display Tweaks; 2024-04-08 18:04:39 -04:00
lwvmobile
eed267ed3f EDACS: Fix TG Hold Value Display if AFS; 2024-04-08 17:34:40 -04:00
lwvmobile
e195770181 M17: Cleanup / Decode IP Frame CONN and DISC; 2024-04-08 16:31:46 -04:00
lwvmobile
cbddea701a M17: Clean Misc Comments / Code / Typos; 2024-04-08 03:50:32 -04:00
lwvmobile
3eefa3365f M17: IP Frame Encoder / Decoder Fixes; 2024-04-08 02:45:47 -04:00
lwvmobile
d22f9ddfe3 M17: UDP IP Frame Decoder over STDIN; 2024-04-07 14:14:44 -04:00
lwvmobile
5c9416313a M17: Decode Extended CSD in Meta; 2024-04-07 04:31:20 -04:00
lwvmobile
4b063aaf97 M17: Decode META Field; 2024-04-07 03:29:37 -04:00
lwvmobile
bbfd4967cf M17: Misc Tweaks with Stream 1600; Misc Other; 2024-04-07 02:22:11 -04:00
lwvmobile
c5742350d1 M17: Use 3200 or 1600 Voice in STR Encoder; 1600 Arbitrary Data Encoder / Decoder; 2024-04-06 22:45:13 -04:00
lwvmobile
753286cdf6 EDACS: Add AFS Configuration Display to Ncurses; 2024-04-06 22:16:47 -04:00
lwvmobile
22028b37ed Variable AFS bit values and shift / mask calculations using -fh344 or -fH434; 2024-04-06 21:26:26 -04:00
lwvmobile
3483c736ba Merge pull request #248 from ilyacodes/afs
EDACS: fix AFS 4:4:3 display
2024-04-06 19:52:36 -04:00
ilyacodes
20989c31c8 EDACS: fix AFS 4:4:3 display 2024-04-06 12:47:46 -04:00
lwvmobile
cee797017b M17 - Misc Code / Comment Cleanup; 2024-04-04 09:20:08 -04:00
lwvmobile
bceac916fe M17 - Tweaks to LSF Frame Decoding; 2024-04-04 08:39:13 -04:00
lwvmobile
7d8a081e3f Convolutional Decoder Init / Tweaks; 2024-04-04 08:38:37 -04:00
lwvmobile
4bd36ece9a M17 - Change -Q / DSP output format to match expected float input to m17-packet-decode; 2024-04-03 00:18:19 -04:00
lwvmobile
b95644d5e5 Re-Enable Analog PBF as default; 2024-04-02 13:56:29 -04:00
lwvmobile
791cc17b27 socat note in example usage 2024-04-02 12:37:00 -04:00
lwvmobile
40b1b67b29 Ncurses Misc Cosmetic Fixes on Analog; 2024-04-02 11:39:35 -04:00
lwvmobile
b8cb4ad521 Add Analog Displays to UDP and OSS Output; 2024-04-02 11:33:28 -04:00
lwvmobile
6b50ca034b Add Note About netcat; 2024-04-02 11:21:33 -04:00
lwvmobile
43df9c3ff5 Set RTL Sample Multiplier Default to 2X; 2024-04-02 10:04:02 -04:00
lwvmobile
dff48692ca Disable Analog PBF as default; 2024-04-01 13:51:24 -04:00
lwvmobile
44a8085463 Seperate CLI switch for Analog Audio Out Gain; 2024-04-01 13:29:10 -04:00
lwvmobile
934eb8264e Fix Audio Smoothing Variable Type; 2024-04-01 13:15:08 -04:00
lwvmobile
dc1bb6a55e CLI Options for Audio Filtering; 2024-04-01 13:11:23 -04:00
lwvmobile
fe9b5b51e8 Reconfigure RTL Volume Multiplier to be more dynamic; 2024-04-01 11:20:25 -04:00
lwvmobile
f35aa046c1 Tweak Ncurses Display Alignment for HPF; Document Keyboard Shortcuts for Filters; 2024-04-01 10:58:26 -04:00
lwvmobile
a708fa5f6e P25: Fix Warnings on MPDU UU_V Ext Grant; 2024-03-30 17:29:08 -04:00
lwvmobile
bb78b1bf27 P25: Fix Extended Channel Grants/Updates/Full SUID Values; 2024-03-30 17:21:10 -04:00
lwvmobile
931fae62c6 NCURSES: '3' Key Slot Preference Cycle; 2024-03-29 18:46:49 -04:00
lwvmobile
c1e657a5e3 DMR: Simplify CON+ Tune Away Logic; 2024-03-29 17:52:31 -04:00
lwvmobile
1e2d42ce23 EDACS: Fix No Color Build Compile Error; 2024-03-28 14:18:12 -04:00
lwvmobile
5d367a5c27 Upload Correct Updated Patches; 2024-03-28 14:17:16 -04:00
lwvmobile
1d03f7efbf Delete Broken / Incomplete Patches Uploaded Last Night; 2024-03-28 14:17:05 -04:00
lwvmobile
5125fd4d6c Delete Outdated Patches; 2024-03-28 14:16:56 -04:00
lwvmobile
d079035adf Update Patches For Easy Application; 2024-03-28 14:16:46 -04:00
lwvmobile
06bfcdacc2 Remove Integrated Patches; 2024-03-28 14:16:30 -04:00
lwvmobile
ab844202bc Squashed commit of the following:
commit 833e0173f24b12a12ff80f9a35fb43107d355cc3
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 22:51:02 2024 -0400

    Fix Slot Preference Depending on Build;

commit 716577ab09c0cee68bca3bcdcbaaa7cfa3be4f97
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 22:27:24 2024 -0400

    M17 - Voice Playback Only If Enabled; Misc;

commit c0f9818cf38ce7f127370f19ec4afa2457cef19a
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 17:39:34 2024 -0400

    Add DMR/P25p2 Stereo Channel Patch;

commit 1a0baf0a17ccf8cc0eb0a01a809269354480d1d1
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 17:37:46 2024 -0400

    Add DMR Cap+ Faster Rest Patch;

commit 9f5b52aa8f20bfe3eab5413f2c3fa41003d53b3c
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 17:36:24 2024 -0400

    Disable EDACS Analog Debug;

commit 7dd0de67b602f0acd111200f838fbb1a0541a8bf
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 17:36:04 2024 -0400

    Squashed commit of the following:

    commit 95d46fb35d6cb6fb0a9825084f4c2accf8edad4a
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Mon Mar 25 17:48:57 2024 -0400

        Enable HPF_D by default; Increase manual analog gain to 50;

    commit 1f37837664e16760b5cbf5653fc4d829ee6cce83
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Mon Mar 25 08:43:17 2024 -0400

        Enable HPF_D on M17 Voice;

    commit 9bbe4de7fd
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sun Mar 24 16:08:16 2024 -0400

        EDACS: Digitize Analog For Analysis of 'Data Burst' Like Behavior;

    commit 9249b7a943
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sun Mar 24 12:28:26 2024 -0400

        Simply Mono Short Playback;

    commit 89ad0f17e3
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sat Mar 23 21:12:44 2024 -0400

        Add HPF to SS4, SS3, and SS Audio Methods;

    commit e8184c7fbd
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sat Mar 23 17:13:44 2024 -0400

        RTL - Add The Sample / Volume Multiplier as a user configurable option;

    commit ee04d11116
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 23:15:04 2024 -0400

        Fix HPF_D so it actually works correctly;

    commit e549b21497
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 20:11:34 2024 -0400

        Make Analog Auto Gain Control Mostly Tolerable;

    commit 2f9e0525fe
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 18:20:38 2024 -0400

        User Toggle HPF on Digital;

    commit ff58d3a6fa
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 18:10:15 2024 -0400

        User Toggles and Displays for Filters;

    commit b6fc17c506
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 15:55:09 2024 -0400

        More Analog Manual Audio Gain Tweaks;

    commit 076b9fbf04
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 06:26:10 2024 -0400

        Add SQL Hit on EDACS if Colors Disabled;

    commit 59fe47ef05
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 02:23:08 2024 -0400

        Disable HPF Test on Digital Voice;

    commit 4a63068ce1
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 23:39:43 2024 -0400

        Misc Code Organizing; audio_gainA Tweaks;

    commit 3585e7e594
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 13:18:31 2024 -0400

        Test Tweak to RTL Sample Multiplier;

    commit fa5b25283f
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 13:18:07 2024 -0400

        Adjust Manual Mic Gain on M17 Encoder; Ncurses Display;

    commit c985fea035
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 12:34:01 2024 -0400

        Misc Notes on using raw_rms values during testing;

    commit b273e5b7be
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 12:31:33 2024 -0400

        Bugfix for EDACS Analog Segfault when using the digitize function for an extended period;

    commit eadf3fdf23
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 10:12:04 2024 -0400

        Analog Gain Has Own Variable; Ncurses Keys; Misc;

    commit 0debcc647e
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 08:49:51 2024 -0400

        Filtering Misc Cleanup;

    commit 98e10b2627
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Thu Mar 21 00:02:21 2024 -0400

        Automatic Gain On Analog WIP; Manual Gain Control;

    commit 89736ae543
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Wed Mar 20 10:22:20 2024 -0400

        Passband Filter Testing on Raw Analog / EDACS / M17 Encoder;

    commit 43f6218129
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Wed Mar 20 09:03:02 2024 -0400

        Passband and Notch Filter Setup; Debug Output;

    commit 35a1b53867
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 22:35:36 2024 -0400

        HPF: Only Use On RTL Input when M17 Encoder Uses It;

    commit b9949f0d80
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 17:31:59 2024 -0400

        Disable LFP on EDACS Analog Out;

    commit 3666740674
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 13:42:07 2024 -0400

        Test HPF On Digital Voice Out;

    commit ef13343925
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 12:46:27 2024 -0400

        RTL_FM Input for Analog/M17 Encoder;

    commit 2b7de90474
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 11:03:55 2024 -0400

        New Analog Audio Filters WIP;

commit 3b9f9f5a3befb295da284379262323fad7d69c7a
Author: lwvmobile <lwvmobile@gmail.com>
Date:   Tue Mar 26 17:33:34 2024 -0400

    Squashed commit of the following:

    commit a5c5be3b955a82cc72f1486ff87d7c1b4893295f
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Tue Mar 26 17:28:35 2024 -0400

        EDACS: Standard display rewrite, parsing/RE fixes, tune i-calls and all-calls (#246)

        * EDACS EA: Fix reversed TDMA/data calls

        * EDACS: deduplicate ncurses printing logic

        * EDACS: pass call state via new state struct field

        * EDACS: RE some differences from Standard spec

        * EDACS: show state for data calls

        * EDACS: tune individual calls on Standard

        * EDACS: tune all-calls on Standard

        * EDACS: properly identify emergency on channel updates

        * EDACS: fix build break

        * EDACS: fix conditions for refreshing the display source

        * EDACS EA: Identify calls as voice for display

        * EDACS: voice channel update emergency refactor

        * EDACS: Show interconnect calls in call log

        * EDACS EA: show unknown data channel assignments in log

        * EDACS: check LCN is not 0 before assigning it

        * EDACS: C operator precedence is dumb

        * Initialize edacs_vc_call_type

        * use j and not i in call_matrix for call history;

        ---------

        Co-authored-by: lwvmobile <lwvmobile@gmail.com>

    commit c8d00846b1
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sun Mar 24 17:48:46 2024 -0400

        EDACS: Display cached call source on Standard, tune group calls on assignment (#241)

        * Trim trailing whitespace

        * EDACS: Display cached call source on Standard

        The logic in `edacs-fme.c` didn't work, in retrospect, because it would have depended on getting back-to-back messages for the same call. In practice, that is unlikely even on an idle system as system state gets displayed.

        Instead, cache on the display end, for a "better" user experience.

        * EDACS: Pad channel freq to "000.000000 MHz"

        * EDACS: Process/tune group calls on assignment

    commit 8d432e8b3e
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sun Mar 24 12:29:22 2024 -0400

        EDACS: ESK fixes, RE of standard channel assignments, cleanups (#238)

        * EDACS: Make i-calls very obvious on standard

        * EDACS: abstract target for Interconnect Channel Assignment

        * EDACS: little shortcut example updates

        * EDACS: Apply ESK to both FR1 and FR4

        * EDACS: Group channel assignment by mode

        * EDACS: Merge MT-A 0/1 and 2/3 cases

    commit 0440dea1de
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sun Mar 24 02:47:09 2024 -0400

        EDACS: Fix Call History For Standard Maybe;

    commit 208f188e55
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 23 21:35:42 2024 -0400

        EDACS: Speculative RE of MT-A value 0, pretty colours (#231)

        * EDACS: fix log formatting

        * EDACS: Speculative RE of MT-A value 0

        * EDACS: CC message pretty colours

        * EDACS: little formatting

        * EDACS: eh make interconnect magenta

    commit 36f76a7e21
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 23 17:35:45 2024 -0400

        EDACS: Fix copy/paste error (#230)

        I went through by hand and I'm confident this is the last of the `get_lcn_status_string()` errors.

    commit 4bc73d8c68
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 23 17:24:32 2024 -0400

        EDACS: Rewrite Standard/Networked parsing per TIA/EIA TSB 69.3 (#229)

        * EDACS EA: refactor log messages for consistency

        * EDACS: Log LCN status values

        * EDACS EA: channel assignment vs update

        * EDACS: Implement TIA/EIA TSB 69.3

        * EDACS: clean up Site ID message

        * EDACS: Actually process call for Channel Update

        * EDACS: Update display for Standard calls

        * EDACS: Format of Voice Group Channel Assignment

        * EDACS Standard: Log LCN status values

        * EDACS: Rebase and fix some issues

        * EDACS: Fix copy/paste error

    commit 03507055a4
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 23 16:05:09 2024 -0400

        EDACS: add EA messages / start mass Standard refactor (#226)

        * EDACS EA: refactor log messages for consistency

        * EDACS EA: channel assignment command (unknown data)

        * EDACS EA: status/message command

        * EDACS Standard: Refactor variable declarations

        * EDACS Standard: log raw payloads for debugging

        * EDACS: Fix typing

        * EDACS EA: update status/message CC command

        * EDACS: Log LCN status values

        * EDACS: String format

        * EDACS EA: channel assignment vs update

        * EDACS: fix syntax error

        * EDACS: change string for reserved LCN status

    commit fbe5fd2093
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Fri Mar 22 15:26:50 2024 -0400

        EDACS EA: emergency calls, MT1 fixes, logging improvements (#221)

        * EDACS EA: Fix i-call MT1 after ESK changes

        * EDACS EA: Fix all-call ncurses display

        * EDACS EA: Make detailed log slightly more readable

        * EDACS EA: Improve colours in logs

        * EDACS EA: Space in logs for consistency

        * EDACS EA: Fix MT1 for analog group voice after ESK change

        * EDACS EA: add parsing for emergency calls

    commit 413e5f76a2
    Merge: de9127c 388a57d
    Author: lwvmobile <59371473+lwvmobile@users.noreply.github.com>
    Date:   Fri Mar 22 06:59:31 2024 -0400

        Merge pull request #220 from lwvmobile/edacs_manual_modes

        Edacs manual modes

    commit 388a57d8fc
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 05:28:11 2024 -0400

        EDACS: Re-enable the -9 switch to maintain user compatability; Fix Missing Bracket on non color mode;

    commit 058099f1aa
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 03:24:57 2024 -0400

        EDACS: Tweak Mode Toggle Display; Add Frame Dump on No Mode Set;

    commit 68aa6b018e
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 02:19:38 2024 -0400

        EDACS: Update Docs to Reflect Changes;

    commit c404f3c48c
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 02:01:09 2024 -0400

        EDACS: Ncurses Display Working Mode Tweaks;

    commit b2d1608eb7
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 01:08:28 2024 -0400

        EDACS: Toggle Keys A and S for Mode Selection;

    commit a4553a0a0a
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Fri Mar 22 00:45:37 2024 -0400

        EDACS: Remove Auto Detect Code; Make CLI Switches;

    commit de9127cfb4
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Thu Mar 21 21:02:53 2024 -0400

        EDACS: support for EA system all-calls (#214)

        * Refactor debug printing a bit

        * Clean up group call logic

        * Minor changes to debug printing

        * EDACS EA: support for system all-calls

        * EDACS: split out MT1 for TDMA call since we can't decode it anyway

        * Refactor identifying call mode (digital/analog)

        * Maintain consistent indentation for all MT1

        * EDACS: Fix Compiler Error.

        Had an extra right bracket on line 383

        ---------

        Co-authored-by: lwvmobile <59371473+lwvmobile@users.noreply.github.com>

    commit c85dd60399
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 17:38:30 2024 -0400

        EDACS: NET/STD LCN > 0 Check;

    commit bed766a86e
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Tue Mar 19 09:34:10 2024 -0400

        EDACS: STD/NET Don't Tune Unless CC LCN Set;

    commit 69f532a022
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Mon Mar 18 11:41:58 2024 -0400

        EDACS: EA I-Call decoding improvements (#205)

        * EDACS: formatting nit

        * EDACS: add name to credits

        * EDACS: Handle initial grant vs grant update for i-call

        * EDACS: consistency for group vs i-call

        * EDACS: file naming for i-call recordings

        * EDACS: EA refactor when MT1 is 0x1F

        * EDACS: check we know CC LCN before leaving it

        * EDACS: fix breaking change for Standard

        Revert mistake in f68367c4f3

        * Fix patent number

        * EDACS: Fix Compiler Error 1;

        Fix Rogue Copy Paste

        * EDACS: Add MT1, MT2, and FR1 and FR4 Dumps on Payload;

        ---------

        Co-authored-by: lwvmobile <59371473+lwvmobile@users.noreply.github.com>

    commit a7de24c47b
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Mon Mar 18 07:47:34 2024 -0400

        EDACS: fixes and improvements to EA analog and i-call parsing (#204)

        * Fix MT1 math given esk_mask value is 0xA0

        * EDACS: Clean up formatting for I-Calls

        * EDACS: typo, fix the TGID for group calls

        Fix copy-pasta

        * EDACS: Fix MT2 for I-Calls

        Incorrectly copied decimal values as hex - obviously MT2 is only 4 bits so it cannot be greater than 15.

        * EDACS: check LCN is > 0 before trying to tune

        An EA CC sometimes includes commands that parse as LCN 0 - but otherwise valid - analog call voice grants for TG 1. Since LCN 0 is not valid, ensure that we don't try to tune to them while we try to figure out what they're about.

        * EDACS: Process "login" message on CC

        Log "login" messages sent on the CC. Verified behaviour against UniTrunker.

    commit 10eacd99cc
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sun Mar 17 18:56:41 2024 -0400

        EDACS: Clean up formatting for I-Calls (#203)

        * Fix MT1 math given esk_mask value is 0xA0

        * EDACS: Clean up formatting for I-Calls

    commit ebe6e8fc65
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sun Mar 17 18:02:12 2024 -0400

        Fix MT1 math given esk_mask value is 0xA0 (#202)

    commit 8619612b76
    Author: lwvmobile <lwvmobile@gmail.com>
    Date:   Sat Mar 16 22:42:44 2024 -0400

        EDACS: Setup Analog Calls and WAVs on EA and ICALL;

    commit 9ac1573f0b
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 16 17:17:14 2024 -0400

        EDACS: Add MT1 value / logging for analog group calls (#198)

        * Add MT1 value / logging for analog group calls

        * Respect user preference for tuning to group calls

        * Revert "Respect user preference for tuning to group calls"

        This reverts commit 83ac8feab7.

    commit 0aa01a45ef
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 16 17:16:52 2024 -0400

        EDACS: Respect user preference for tuning to group calls (#201)

    commit f68367c4f3
    Author: ilyacodes <33097525+ilyacodes@users.noreply.github.com>
    Date:   Sat Mar 16 17:16:20 2024 -0400

        EDACS: Add parsing for individual calls (#200)

        * EDACS: Add parsing for individual calls

        This change adds parsing for I-Calls on EA systems. Both analog and ProVoice modes are parsed and processed. See related issue for discussion.

        * Respect user preference for tuning to private calls

        * EDACS: Respect user preference for tuning to private calls

        * EDACS: Handle i-call target in ProVoice logging

        * EDACS: Show i-calls distinctly from group calls
2024-03-26 22:59:05 -04:00
ChronosXYZ
f05ddf8fcd Add Nix flake for the project (#232)
* Add Nix flake for the project

* Add `codec2` library for M17 encoding support
2024-03-23 22:13:12 -04:00
lwvmobile
f36df3ea09 NCURSES - Voice Error as Trunc Value to perserve display uniformity; 2024-03-19 18:05:36 -04:00
lwvmobile
df28ebe573 M17 - PKT CRC Immediately Following Terminator Byte and Fixes; 2024-03-17 19:28:53 -04:00
lwvmobile
3a44affc63 Fix/Simplify/Trash Legacy 48k Upsample Functions; 2024-03-15 22:22:06 -04:00
lwvmobile
19be1db46c M17 - IP Frame WIP2; 2024-03-15 19:16:44 -04:00
lwvmobile
7101c3588a M17 - Enable Vox Mode for Voice Stream (testing); 2024-03-15 17:43:53 -04:00
lwvmobile
5573244583 M17 - Transmuting Examples; Add Passive Analog Monitor Mode -fA; 2024-03-15 13:09:56 -04:00
lwvmobile
ad1db34c86 M17 - Make Input Rate Configurable via -M M17 User String. 2024-03-15 11:31:33 -04:00
lwvmobile
379cc25099 M17 - Update Example Page to Include Using M17 Encoder/Decoder; 2024-03-14 19:58:41 -04:00
lwvmobile
df6a6ce066 M17 - Persistent TCP Retry When M17 Decoding Enabled; 2024-03-14 19:32:07 -04:00
lwvmobile
27735ccc01 Merge pull request #197 from LZ2DMV/patch-1
Update Example_Usage.md
2024-03-14 17:48:14 -04:00
LZ2DMV
d614eb088e Update Example_Usage.md
Add example for recording 48k/1 audio with rtl_fm
2024-03-14 22:47:29 +02:00
lwvmobile
f1088e9471 M17 - Fix Symbol Stream to be compatible with m17-packet-encode.c from m17_implelemtations; 2024-03-14 07:10:43 -04:00
lwvmobile
f6b8cc71cc M17 - Fix Binary Output to Append; 2024-03-13 10:29:13 -04:00
lwvmobile
d35144e0e9 M17 - Fix PKT CRC +1 on len value; Output Binary Bitstream to file with -Q option; 2024-03-13 10:22:55 -04:00
lwvmobile
f7fe1e066c M17 - Fix Char Array Size Compiler Warnings; 2024-03-12 22:19:13 -04:00
lwvmobile
18366dd294 M17 - Fix PKT Decoder PBC to Internal Counter; 2024-03-12 22:05:17 -04:00
lwvmobile
106d717157 M17 - Implement RRC Filtering; 2024-03-12 21:22:29 -04:00
lwvmobile
296775d231 M17 - Do not include Data Type Byte in PKT CRC; 2024-03-12 17:48:58 -04:00
lwvmobile
114d8d7dfc M17 - Fix / Initialize User Input Strings and Fix CAN Value; 2024-03-12 17:48:38 -04:00
lwvmobile
2392f57d62 M17 - Check Caps and Special CSD Values; 2024-03-12 14:20:58 -04:00
lwvmobile
a0b199d208 M17 - Allow LSF Decode on CRC Err if AF Bypass Enabled; 2024-03-12 14:05:20 -04:00
lwvmobile
6c4584a00a M17 - User CAN/DST/SRC and SMS at CLI; 2024-03-12 13:46:55 -04:00
lwvmobile
5d565c55a7 M17 - Fix PKT CRC to only include significant bytes; 2024-03-12 09:16:15 -04:00
lwvmobile
fbc902d16e M17 - Misc Cleanup and Disable Debug Messages; 2024-03-11 09:23:53 -04:00
lwvmobile
051a65f0bb M17 - Fix Misc PKT/SMS Encoding/Decoding Issues; 2024-03-11 09:09:14 -04:00
lwvmobile
ffc311e0e9 M17 - Fix CSD Encode For Reserved Values; 2024-03-11 06:45:55 -04:00
lwvmobile
d738eee5d9 M17 - Fix Cygwin M17 FrameSync Woes; (Initialize Synctest); 2024-03-10 20:31:30 -04:00
lwvmobile
58a00106d3 M17 - Packet Encoder and Decoder Misc Fixes; 2024-03-10 04:51:08 -04:00
lwvmobile
d0617714ca M17 - Packet Decoder WIP3; SMS Decoder; Fix Encoder strlen value; 2024-03-10 04:00:25 -04:00
lwvmobile
6ae3316cd1 M17 - Packet Decoder WIP2; 2024-03-10 03:43:30 -04:00
lwvmobile
c1577905cd M17 - Packet Decoder WIP; 2024-03-10 01:39:42 -05:00
lwvmobile
d12f6a1191 M17 - Simple Packet Encoder; 2024-03-10 00:56:27 -05:00
lwvmobile
0f5612fdd4 M17 - Simple BRT Encoder; Setup for PKT Encoder; 2024-03-09 19:38:09 -05:00
lwvmobile
a77fa83c80 M17 - Add PKT/BRT FS on Encoder; Reorganize RF Type Numbers; 2024-03-09 17:27:08 -05:00
lwvmobile
75bc2b7b35 M17 - Tweak Dead Air; Disable Non-Zero Fill; 2024-03-08 16:34:22 -05:00
lwvmobile
ac6284819a M17 - Misc Tweaks; 2024-03-08 11:13:05 -05:00
lwvmobile
2e09e5fdfa M17 - Non Zero Fill on LSF Meta Field; 2024-03-08 10:37:29 -05:00
lwvmobile
5c09130782 M17 - Implement libM17 Viterbi Decoder for LSF; 2024-03-08 09:41:19 -05:00
lwvmobile
677b064e97 M17 - Include libM17 Viterbi Decoder and Misc Math; 2024-03-07 22:22:19 -05:00
lwvmobile
a30512f4e4 M17 - Debug LSF Frame; Pack/Repack CRC; 2024-03-07 21:21:06 -05:00
lwvmobile
e20229208f M17 - Update Ncurses Terminal manually if not using internal decoder; 2024-03-07 13:40:40 -05:00
lwvmobile
f67bb81de2 M17 - Tweak Encoder Output WAV during deadair; 2024-03-07 12:29:09 -05:00
lwvmobile
f98cdfeb0f M17 - Encoder Add Forgotten Lines; 2024-03-07 11:50:30 -05:00
lwvmobile
ba264c1557 M17 - Audio RF Modulation(WIP2); Disable Current M17 Filter; Misc; 2024-03-07 11:19:59 -05:00
lwvmobile
11a08298ff M17 - Audio RF Modulation(WIP); 2024-03-07 01:24:59 -05:00
lwvmobile
72ac2f628b M17 - Fix FSN Variable Type; 2024-03-06 20:18:10 -05:00
lwvmobile
dd87bf77f8 M17 - Tweak Nonce/IV Warning; 2024-03-06 14:45:26 -05:00
lwvmobile
d730ca2c25 M17 - Flush Stored Decoder Meta when not Encoding; 2024-03-06 13:21:27 -05:00
lwvmobile
0d09baee3c M17 - Repack LSF Frame Before New Encoding Session; 2024-03-06 13:14:07 -05:00
lwvmobile
7ea26b68e7 M17 - Send New LSF on new Encode; EOT Bit Fixes; Cleanup; 2024-03-06 12:59:54 -05:00
lwvmobile
e7334a6c4f M17 - Misc Cleanup and Reference Updates; 2024-03-06 11:52:53 -05:00
lwvmobile
404dc772d4 M17 - IP Frame EOT/FN Fix; EncodeRF Prototype; Misc; 2024-03-06 10:44:30 -05:00
lwvmobile
7754123e30 M17 - LSF Encode (WIP); Initial FSN Bug Fix; Misc; 2024-03-05 22:23:08 -05:00
lwvmobile
16b950d5a0 M17 - Fix Encoder Nonce Refresh; 2024-03-05 20:32:29 -05:00
lwvmobile
0ba3fee968 M17 - IP Frame and UDP Socket Connect/Blaster(WIP); 2024-03-05 16:00:35 -05:00
lwvmobile
a2113fcdcc M17 - AES IV Replay Warning; 2024-03-05 12:44:19 -05:00
lwvmobile
ec7fbeeb22 M17 - Add Nonce to Encoder; 2024-03-05 12:27:40 -05:00
lwvmobile
5f969bf4aa M17 - Cleanup; Audio Tweaks; Fix Conv; Misc; 2024-03-02 19:26:48 -05:00
lwvmobile
8a197aea45 M17 - M17 STR Encoder Nucrses Support; 2024-03-02 02:21:38 -05:00
lwvmobile
c6bc10f1ba M17 - M17 STR Encoder and Playback (WIP); 2024-03-01 23:55:09 -05:00
lwvmobile
5830dfa991 M17 - Fix UDP Audio Output Type; 2024-03-01 23:29:28 -05:00
lwvmobile
fc44edb0fc Remove Old/Obsoleted Patches; 2024-02-27 09:04:25 -05:00
lwvmobile
cb02c0328c P25 - Better Handling of Trunking ENC Call Lockout; Fix Duplicate Channel Listing in Multi Grant Updates; 2024-02-27 08:57:15 -05:00
lwvmobile
71d79ff45b Update Patch For Testing; Remove Old Patches; 2024-02-21 15:57:48 -05:00
lwvmobile
c4e2730ced P25p2 - Trunking Slot Enabled Tweak; 2024-02-21 15:28:07 -05:00
lwvmobile
65fdd7c5b4 UDP Analog Audio Output; 2024-02-21 10:29:06 -05:00
lwvmobile
42fee3bd3e Merge pull request #191 from axpe95/audio_work
In MBE calls set err2 to hold accumulated value of errors
2024-02-21 09:33:50 -05:00
axpe95
b4d45af268 MBE calls set err2 to hold accumulated value of errors 2024-02-20 17:45:54 -08:00
lwvmobile
7125f2fa5e DMR - Con+ Fix Setting CC Frequency Condition; 2024-02-20 07:34:52 -05:00
lwvmobile
4993ed00a2 DMR - Con+ Call Grant TS Value Fix; 2024-02-19 14:45:53 -05:00
lwvmobile
a2b622a343 DMR - Con+ Tune Timeout / Return to CC Tweaks; 2024-02-19 14:32:11 -05:00
lwvmobile
c401035209 NXDN - Rolling CAC CRC fix (reset demodulator state); Scrambler SEED Fix Each PF; 2024-02-14 18:03:07 -05:00
lwvmobile
4324afc593 Merge pull request #189 from axpe95/decrypt_fix
fix nxdn scramber roll on facch1 after superframe
2024-02-14 13:17:16 -05:00
lwvmobile
de5b99dbb9 EDACS and Analog Monitoring - Apply Filtering Stack (DE,DC,PE, CL); Misc; 2024-02-12 13:18:56 -05:00
lwvmobile
374999df1f EDACS - Implement TCP Connection Error Checking on Analog; Misc Cleanup; 2024-02-11 14:08:23 -05:00
lwvmobile
ba7455c99e EDACS - Analog Audio and EOT Tweaks; Fix Rigctl SetMod; 2024-02-11 08:42:32 -05:00
axpe95
ad592cdc59 fix nxdn scramber roll on facch1 after superframe 2024-02-09 16:19:42 +02:00
lwvmobile
78b2dac71c Upload Experimental Patches For Testing; 2024-02-09 09:13:53 -05:00
lwvmobile
5d5f224f66 Merge pull request #188 from axpe95/audio_out_fix
Fix output to stdout
2024-02-09 08:56:47 -05:00
axpe95
c70762fbee Fix output to stdout 2024-02-09 15:07:17 +02:00
lwvmobile
166bbbbc72 DMR - P_Clear wait by trunk hangtime; RC PDU tweak; 2024-02-05 23:24:59 -05:00
lwvmobile
8bdcaa047a DMR - P_Clear Wait One Second on Initial Tune; 2024-02-05 14:17:48 -05:00
lwvmobile
ee557cc552 DMR - P_Clear Reorder TG Hold Priority; 2024-02-05 13:14:03 -05:00
lwvmobile
d7b99be51f Update Screenshots; Remove Old Patches; 2024-02-05 12:18:31 -05:00
lwvmobile
ed85d508ed DMR rc crc7 fix and rc element decode #187; fix/revamp p_clear and p_protect trunking logic; MTL patch; g_dmr patch; Misc; 2024-02-05 11:11:56 -05:00
lwvmobile
ffa8b053d7 Fix minor memory leak on timestr; 2024-01-30 23:43:32 -05:00
lwvmobile
c39ddbc7a7 P25p1 MFID90 Channel User; TG Hold CLI; DMR BS Stablilization and LE Fix; Updated Patches; OSS Jank Fix; Ncurses Keyboard Shortcuts for Return to CC and Manual Channel Cycling; Misc; 2024-01-27 16:54:01 -05:00
79 changed files with 12751 additions and 4629 deletions

2
.gitignore vendored
View File

@@ -8,3 +8,5 @@ examples
*.bin
*.ans
*.patch
*.zip
result

View File

@@ -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})

View File

@@ -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.
![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/audio_work/dsd-fme2.png)

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 721 KiB

View 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.
![Audio 1](https://github.com/lwvmobile/dsd-fme/blob/aw_dev/examples/pavucontrol_plumbing1.png)
![Audio 2](https://github.com/lwvmobile/dsd-fme/blob/aw_dev/examples/pavucontrol_plumbing2.png)
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. -->

View File

@@ -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.

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -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
View 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
View 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 { };
};
};
}

View File

@@ -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
View 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;
};
}

View 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')

View 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");

View 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);

View File

@@ -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;
+ // }
}

View File

@@ -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;
}
}

View 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);

View File

@@ -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", "");

View File

@@ -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", "");

View 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

View 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;

View File

@@ -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
View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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+ ");

View File

@@ -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
}

View File

@@ -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

View 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)
{

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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];

View File

@@ -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);
}

View File

@@ -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 &lt
//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, &lt, &err);
else opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, dev, opts->output_name, &cc, NULL, &lt, &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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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);

View File

@@ -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)

File diff suppressed because it is too large Load Diff

View File

@@ -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 ");
}

View File

@@ -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
View 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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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]];
}

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

3216
src/m17.c

File diff suppressed because it is too large Load Diff

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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++)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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/

View File

@@ -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");

View File

@@ -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))

View File

@@ -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)

View File

@@ -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");

View File

@@ -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

View File

@@ -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
View 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;
}

View File

@@ -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;

View File

@@ -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);