832 Commits
446 ... 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
lwvmobile
fa7fd116a7 Update/Fix Some Docs; 2023-12-28 17:38:18 -05:00
lwvmobile
199913ce53 Remove Colon (:) from mbe output files (hh:mm:ss); 2023-12-28 17:20:47 -05:00
lwvmobile
1ac2d84dc0 DMR - Fix TIII Adj/Vote Online Offline Indicators; 2023-12-28 03:22:08 -05:00
lwvmobile
c55128fc21 Patch - Restore Correct Wolf Patch; 2023-12-27 18:26:01 -05:00
lwvmobile
a6cb8b6989 Patch - Delete Broken Wolf Patch; 2023-12-27 18:24:50 -05:00
lwvmobile
676c5f0f09 Patch - Cleanup Old/Obsolete Patches; 2023-12-27 18:08:52 -05:00
lwvmobile
9acc014274 Patch - Even More TDMA (DMR/P2) Mono Stereo Tests; 2023-12-27 18:05:23 -05:00
lwvmobile
2237d16696 Patch - More TDMA (DMR/P2) Mono Stereo Tests; 2023-12-27 05:26:24 -05:00
lwvmobile
180fd1bfb0 DMR - More Compact Vendor/Site Info Ncurses; 2023-12-27 04:05:46 -05:00
lwvmobile
77bcff0dcc Patch - Fix g_dmr patch for current updates; 2023-12-26 21:08:56 -05:00
lwvmobile
b43e566f98 Patch - Test DMR Mono/Stereo Interleaving; #181 2023-12-26 20:55:59 -05:00
lwvmobile
f4e0412368 DMR - Rework C_ALOHA, SYSCODE and C_BCAST; #182 2023-12-26 15:54:18 -05:00
lwvmobile
18ec24f0e8 P25 -- TSBK Payloads on MFID90/A4 Known Opcodes; 2023-12-26 02:26:33 -05:00
lwvmobile
bf10289223 DMR - Con+ CSBK and Tuning Tweaks; Data Grant; 2023-12-24 20:55:11 -05:00
lwvmobile
e3c3d15dce DMR - Move CSBK Acknowledgements to Non MFID10; 2023-12-23 15:04:01 -05:00
lwvmobile
b726cc8faf DMR - Fix UDT Dialer Digit Values; 2023-12-23 13:45:27 -05:00
lwvmobile
133746d3a3 DMR - Acknowledgement CSBKs; 2023-12-23 12:34:23 -05:00
lwvmobile
56adbfe6fd DMR - Fix Line Break on SLC CRC ERR; 2023-12-23 06:28:59 -05:00
lwvmobile
c2e5b919d6 DMR - PROP_PDU Block Count Sanity Checks; 2023-12-23 05:47:12 -05:00
lwvmobile
b675a8fbcd DMR - Moto Data Channel CSBK; 2023-12-22 18:21:44 -05:00
lwvmobile
d5d84d598e DMR - Fix Data Header Padding Octet Count(try 2); 2023-12-22 18:05:33 -05:00
lwvmobile
aac17ca47d DMR - Fix Data Header Padding Octet Count; 2023-12-22 17:57:08 -05:00
lwvmobile
ead9bb77ec DMR - Only Apply LE MI if CRC4 is Good; 2023-12-22 14:09:40 -05:00
lwvmobile
91aac9b61a DMR - Clarify UDT Data Types; #177 2023-12-20 16:20:33 -05:00
lwvmobile
d0aa9e66ca DMR - Tweak T3 Tuning Conditions; 2023-12-20 12:42:17 -05:00
lwvmobile
b8f92e9661 DMR - Moto Data Announcement CSBK; 2023-12-19 18:28:42 -05:00
lwvmobile
78cb583a4d DMR - DPF 15 P_SAP 1 (prop pdu reserved) Tweaks; 2023-12-19 18:19:34 -05:00
lwvmobile
69f6710898 DMR - Enable LIP Protocol Decoder on UDT; 2023-12-18 20:37:35 -05:00
lwvmobile
ca3c648e3a Remove Some Duplicate FEC Functions (fec.h); 2023-12-18 20:37:31 -05:00
lwvmobile
cc581637c5 Fix Misc Format/Tab Issues on dsd_gps.c; 2023-12-18 18:42:47 -05:00
lwvmobile
5a05011992 DMR - Inplement LIP; Reorganize Various GPS Reports; 2023-12-18 18:35:53 -05:00
lwvmobile
daa200d655 Misc NMEA and Harris 'NMEA' GPS Fixes/Tweaks; 2023-12-17 22:58:59 -05:00
lwvmobile
34b0040b04 P25 - Harris GPS WIP3; 2023-12-17 18:52:13 -05:00
lwvmobile
24c08dfbbd Misc Cleaning; 2023-12-17 15:29:44 -05:00
lwvmobile
390c7939f9 DMR - Fix Inbound CSBK BS_DWN_ACT and Outbound TD_GRANT; 2023-12-17 15:05:11 -05:00
lwvmobile
fa6fe06068 DMR - Misc UDT / NMEA Cleanup; 2023-12-16 22:48:40 -05:00
lwvmobile
7193bca136 DMR - UDT Fixes and NMEA Support; #177 2023-12-16 20:06:10 -05:00
lwvmobile
67b7272b05 DMR - UDT Format Handling WIP2; #177 2023-12-16 08:49:05 -05:00
lwvmobile
88c9959e8e DMR - UDT Format Handling WIP; #177 2023-12-16 08:24:19 -05:00
lwvmobile
e4dcad7873 Patch -- DMR Per Call Ext Custom Dir Fix; #172 2023-12-15 09:11:32 -05:00
lwvmobile
bd1f6881ce DMR - Fix UDT Block Assembly; #177 2023-12-15 09:04:27 -05:00
lwvmobile
4b7b5d5a29 Fix Readme Links; 2023-12-13 12:20:15 -05:00
lwvmobile
42c5bd16cd Update Misc Docs/Scripts/Pics; 2023-12-13 12:17:50 -05:00
lwvmobile
501e7c762c P25 -- TSBK Status Dibit; Misc Cleanup; 2023-12-12 16:07:36 -05:00
lwvmobile
a01a01b533 P25 -- Fix MPDU Valid Dibit/Status Dibit Gathering; 2023-12-12 13:39:40 -05:00
lwvmobile
6d56db17f4 P25 - Harris GPS WIP2; SYNC_BCST Misc; 2023-12-11 11:15:15 -05:00
lwvmobile
d0040fd2a1 LRRP - Fix Speed Variable; Tweak Output; 2023-12-09 13:07:52 -05:00
lwvmobile
e5dd5eed5d P25p2 -- Harris GPS vPDU (WIP); 2023-12-04 07:39:57 -05:00
lwvmobile
dda84e74bc Fix Audio_Work Debian Installer Script; 2023-12-01 09:21:50 -05:00
lwvmobile
19712bf401 P25 - Fix SNDCP Ann vPDU + Misc LCW/TSBK/MPDU; 2023-11-27 11:42:18 -05:00
lwvmobile
76b6aa46bd DMR/P25 - 34 Point[0] fix; crc_valid array size; 2023-11-26 12:01:07 -05:00
lwvmobile
20ca710523 Symbol Sample Edge; YSF/DMR Edge Tweak; RTL Tweak; 2023-11-26 07:22:21 -05:00
lwvmobile
f98bad18b9 P25 - Phase 2 CC to Phase 1 SNDCP Channel Timing; 2023-11-24 16:18:56 -05:00
lwvmobile
0ecc9765dd P25 - R34 MPDU Format WIP2; 2023-11-24 15:52:54 -05:00
lwvmobile
5d26333676 P25 - R34 MPDU Format WIP; 2023-11-23 20:48:53 -05:00
lwvmobile
2d2af754c5 P25 - SNDCP Data Channel vPDU/TSBK WIP; 2023-11-23 02:51:30 -05:00
lwvmobile
3939a5b1cf Patch - DMR Voice and Data Call Presist Upd; #174 2023-11-22 16:13:53 -05:00
lwvmobile
fc99153c80 RTL LP Tweaks; 2023-11-22 12:42:37 -05:00
lwvmobile
076c7d669b DMR - Cap+/XPT Misc Tuning/Reset Tweaks; 2023-11-22 12:21:41 -05:00
lwvmobile
c8020c76ae Sample/Symbol Tweaks; 2023-11-22 07:50:53 -05:00
lwvmobile
696c9663dd Raw Signal Monitor Tweak; 2023-11-22 06:48:56 -05:00
lwvmobile
92144ee482 Patch - DMR Voice and Data Call Presistency; #174 2023-11-21 18:35:22 -05:00
lwvmobile
bd0b3f2856 P25 - MFID90 Moto Talker EOT ; Misc; 2023-11-20 21:49:58 -05:00
lwvmobile
529148ee18 Patch - Fix DMR TII Per Call for G; #172 2023-11-19 13:57:01 -05:00
lwvmobile
810aa04eb0 Fix Quiet WAV file on AERO/OSS when dual voices; 2023-11-19 03:27:39 -05:00
lwvmobile
20abfd4b8e NXDN -- Secondary 1/2 on F2, F3, and SCCH; Misc; 2023-11-18 22:26:26 -05:00
lwvmobile
bb76449560 NXDN -- Fill Out VoiceCallOption; Misc Tweaks; 2023-11-17 22:15:58 -05:00
lwvmobile
fc6b35c7f5 EDACS - Misc Tweaks; 2023-11-17 17:26:43 -05:00
lwvmobile
e6da485117 NXDN -- Implement Secondary 1/2 Decoder; Misc; 2023-11-15 16:21:25 -05:00
lwvmobile
d6160f7b7a NXDN - Zero TG/RID on TX_REL; Misc; 2023-11-15 12:30:01 -05:00
lwvmobile
2aedef7e77 NXDN - Rework Portions of Alias and Call History; 2023-11-14 21:20:55 -05:00
lwvmobile
11fd605d6b Misc Line Break Fixes; SB/RC FEC Output Fix; 2023-11-13 14:37:17 -05:00
lwvmobile
7b87ecca87 DMR - Decode ACT_UPDT SLC; 2023-11-12 08:45:31 -05:00
lwvmobile
ea996f6442 patch - add autodiag's dmr key by cc patch; 2023-11-10 18:53:42 -05:00
lwvmobile
e0182068b2 DMR -- initialize dmr_color_code variable; 2023-11-10 15:08:54 -05:00
lwvmobile
cd01902023 DMR and P25p1 - Tweak Output on Embedded GPS; 2023-11-07 13:10:33 -05:00
lwvmobile
5e386e90e0 Ncurses - Fix DMR MS Display 'Uniformity'; 2023-11-07 12:41:20 -05:00
lwvmobile
e28121f5b3 P25p2 -- Dual Voice Slots when Trunking patch; 2023-11-03 16:17:37 -04:00
lwvmobile
7a25e5d998 EDACS -- Fix/Tweak Analog Calls and Ncurses; 2023-11-03 16:13:04 -04:00
lwvmobile
c6488a4a26 EDACS - Fix Wav File Names, Display AFS as Dec; 2023-11-03 09:10:41 -04:00
lwvmobile
f32d18a5a3 P25p1 -- Fix Bad Copy/Paste Job in LDU1/LDU2; 2023-11-02 12:02:11 -04:00
lwvmobile
3297bd1e9e Patch Folder; NXDN Alias to gN; Patch Docs; 2023-10-31 23:35:27 -04:00
lwvmobile
6f9ce1f7ad NXDN -- Fix Tune Blocking on SRC ID; 2023-10-30 20:44:49 -04:00
lwvmobile
a21d0ac05e P25p1 -- Disable SoftID to gN if Trunking; #166 2023-10-30 15:57:51 -04:00
lwvmobile
584ca9e17a NXDN -- Fix ENC LO; Tweaks/Misc; #121 2023-10-30 10:58:52 -04:00
lwvmobile
fb1abfbd26 P25p1 -- Tweak APX(Moto) LCW GPS Output; 2023-10-28 17:30:09 -04:00
lwvmobile
e6dd71f338 Fix Potential Compiler Error on isch_map; 2023-10-28 17:11:43 -04:00
lwvmobile
46bf41fe15 P25/DMR -- Fix P1 APX GPS; Revert DMR GPS; 2023-10-28 17:11:06 -04:00
lwvmobile
01b6eccf4c NXDN - Misc Tweaks (Ncurses, DISC) and 96Filter; 2023-10-28 01:10:32 -04:00
lwvmobile
e1924db1ff DSTAR - More Eternal Darkness on APRS; #164 2023-10-25 15:22:25 -04:00
lwvmobile
76309399b0 DSTAR - Fix some SD Format Issues; Lose My Mind; 2023-10-25 10:49:36 -04:00
lwvmobile
9cbb4ec36b DMR/P25 - Fix EGPS Lat; Dump to LRRP file; #163 2023-10-24 18:27:36 -04:00
lwvmobile
973af860cf P25p1 -- Soft ID to groupName ifdef; #166 2023-10-24 17:50:35 -04:00
lwvmobile
bc90ade337 Aero -- Fix Date/Time on Per Call Wav Files; #168 2023-10-24 14:36:23 -04:00
lwvmobile
ab54b2f6f8 P25 MFID90 Misc TSBK/LCW and Tweaks; #164 2023-10-24 13:18:05 -04:00
lwvmobile
72626546c5 P25 - Fix MPDU TELE_INT_CH_GRANT elseif condition; 2023-10-21 14:40:49 -04:00
lwvmobile
c08dcb064c P25p1 - Zero LSD if Enc Voice; #166 2023-10-21 13:38:28 -04:00
lwvmobile
7525735df1 P25 - TELE_INT_CH_GRANT; Add/Tweak Misc vPDUs; 2023-10-21 10:37:19 -04:00
lwvmobile
f28559ae6b P25 -- Harris GRG TSBK and vPDU P/S Fix; 2023-10-19 18:43:15 -04:00
lwvmobile
e8957aa90f Multi -- Indicate Mute Code On TG Hold; #132 2023-10-19 12:42:24 -04:00
lwvmobile
4fdc302809 NXDN48 Filter to dPMR Filter; 2023-10-18 17:01:36 -04:00
lwvmobile
c32b2bd7aa WIP: Mute Audio from Blocked TG; 2023-10-17 17:29:58 -04:00
lwvmobile
a121f33be8 Tweak some Verbage regarding the 'Scan' Function; 2023-10-14 09:28:53 -04:00
lwvmobile
f65e65fb47 P25 -- Harris TA to groupName/group.csv; Tweaks; 2023-10-14 08:59:20 -04:00
lwvmobile
a4ddcd4220 P25 -- Tweak to Synchronization Broadcast PDU; 2023-10-13 16:27:20 -04:00
lwvmobile
481dd0adb5 Misc Audio2/Frame Tweaks; 2023-10-12 23:34:40 -04:00
lwvmobile
001d28aaf8 P25p2 -- Disable Slot Synthesis when MAC_SIGNAL; 2023-10-10 09:12:28 -04:00
lwvmobile
86e0a3ad77 Version Update; Compiler Warning Fix; 2023-10-09 17:48:30 -04:00
lwvmobile
a6a300e7c5 P25p1 -- LSD Parity Check; #166 2023-10-09 17:35:11 -04:00
lwvmobile
55a1d5a9f3 P25p2 -- Harris Talker Alias; Misc Frame Tweaks; 2023-10-09 07:46:28 -04:00
lwvmobile
81f9cd6ee6 P25p1 -- WIP: Dump LSD and Soft ID; #166 2023-10-09 07:43:08 -04:00
lwvmobile
459151b4bf P25p2 -- Revert Frame Tweak (SACCH vs Voice); 2023-10-07 01:45:40 -04:00
lwvmobile
fcad1789dc TG Hold: Fix EDACS/NXDN Display and Set; #132 2023-10-06 12:01:36 -04:00
lwvmobile
1c3204e5d7 P25p1 -- Re-Enable Slots on Call Termination; 2023-10-06 10:52:49 -04:00
lwvmobile
84df9bbca7 P25p2 -- Slot ON/OFF During Realtime Tuning; 2023-10-06 10:43:13 -04:00
lwvmobile
d073e7cae8 P25p2 -- Misc Frame Tweaks; 2023-10-06 09:09:31 -04:00
lwvmobile
3c2ce0bb18 P25 -- Disable UU_V Grants when TG Hold; 2023-10-06 08:54:00 -04:00
lwvmobile
9aee34a501 P25p1 -- Disable Heuristics (again) 2023-10-06 07:00:55 -04:00
lwvmobile
cc5248e958 P25p2 -- MAC_END_PTT go to CC conditions; 2023-10-05 15:34:05 -04:00
lwvmobile
d880d05ea5 EDACS/PV -- Dotting Sequence Tweaks; 2023-10-05 13:22:55 -04:00
lwvmobile
d882962b9c NXDN Type-C -- LO Trunked Enc Calls WIP; #121 2023-10-05 10:35:25 -04:00
lwvmobile
241cc05f80 P25 -- TG Hold Support; #132 2023-10-05 10:13:39 -04:00
lwvmobile
cdcdc106ef EDACS -- TG Hold Support; #132 2023-10-05 08:35:04 -04:00
lwvmobile
a6bb5ed28d NXDN -- TG Hold Support for Type-D; #132 2023-10-05 08:29:51 -04:00
lwvmobile
e1348b838b NXDN -- TG Hold Support for Type-C; #132 2023-10-05 08:28:24 -04:00
lwvmobile
677ad50f79 DMR -- LO Trunked Enc Calls WIP; #121 2023-10-04 14:06:52 -04:00
lwvmobile
6903d230fa DMR -- Data Call String Tweak; 2023-10-04 10:31:29 -04:00
lwvmobile
b2cc2d4c11 DMR -- Tweak P_CLEAR Return to CC Conditions; 2023-10-02 12:23:04 -04:00
lwvmobile
763d28981c P25 -- Remove old 1/2 Block Code; Misc; 2023-10-02 09:55:52 -04:00
lwvmobile
f274f74f44 P25 -- Cleanup 1/2 Rate Decoding; 2023-10-02 08:58:03 -04:00
lwvmobile
9dfbcc886f DMR -- Implement Best/Surviving Path on 3/4 Rate; 2023-10-02 08:32:34 -04:00
lwvmobile
5e0f64a7c2 Update Install Scripts with ki4hyf tweaks; 2023-10-01 17:02:13 -04:00
lwvmobile
18f24215e5 Convolutional Decoder Tweaks/Tests; 2023-09-28 11:27:18 -04:00
lwvmobile
23e1c23789 P25 -- Fix SSB vPDU/TSBK; 2023-09-26 19:21:32 -04:00
lwvmobile
a46523ee84 P25 -- Attempt to Fix vpdu.c Tab Alignment; 2023-09-26 18:20:21 -04:00
lwvmobile
dc9aa270e5 P25 -- Misc Tweaks to MFIDA4/90 MAC PDUs; 2023-09-26 18:10:34 -04:00
lwvmobile
ae528f844f P25 -- Tweak MFID A4 MAC GRG Exp Enc; 2023-09-26 17:39:52 -04:00
lwvmobile
d52c2b6426 P25 -- Add MFID90 GRG Call Grant TSBK/MPDU; 2023-09-26 16:54:17 -04:00
lwvmobile
29cd61fdcd P25 -- Fix Alignment; Fix Compiler Warning; 2023-09-26 08:54:08 -04:00
lwvmobile
daecac1612 P25 -- Check MFID 90/A4 Opcode/Payload; Tweaks; 2023-09-26 08:44:57 -04:00
lwvmobile
abbf153785 P25 -- Fix Minor Annoyance, Take 2; 2023-09-25 16:48:44 -04:00
lwvmobile
1667019662 P25 -- NAC/CC Minor Annoyance Fix; 2023-09-25 16:40:52 -04:00
lwvmobile
e2fbece993 P25p1 -- Tweak to 1/2 Rate Decoder; 2023-09-25 15:12:08 -04:00
lwvmobile
d157dee956 DMR - Tweak/Fix T3 Active Data Ch String CSBK_O; 2023-09-20 18:49:04 -04:00
lwvmobile
9506bd5f77 Fix Compiler Errors if librtlsdr not found; 2023-09-20 03:39:03 -04:00
lwvmobile
2222d86e02 P25 - SITE/RFSS Values Decimal in Console/Log; 2023-09-18 11:21:59 -04:00
lwvmobile
2161c3d762 RTL RMS Tests to Reduce CPU Usage; 2023-09-18 10:51:22 -04:00
lwvmobile
eb5de342ba DMR - Cap+/XPT Set TG on Tune for Hold Handling; 2023-09-17 02:40:42 -04:00
lwvmobile
2ca9117783 DMR - Tweak to P_CLEAR Return to CC; Tuner Status; 2023-09-17 02:17:15 -04:00
lwvmobile
b1809e9403 DMR - Add TG Hold Handling To XPT SLC; 2023-09-17 02:09:30 -04:00
lwvmobile
d1b11bc53c DMR - Add TG Hold Handling To Cap+ SLC; 2023-09-17 02:08:37 -04:00
lwvmobile
c61d2dd35d Revert DMR 34 Rate FEC Tests; 2023-09-16 22:34:59 -04:00
lwvmobile
d8958662d9 Disable Debug Output on DMR 34 Rate FEC Tests; 2023-09-16 05:33:33 -04:00
lwvmobile
801cdead80 Test FEC on P25 12 Rate Data; 2023-09-16 05:30:07 -04:00
lwvmobile
5098cdb445 Test FEC on DME 34 Rate Data; 2023-09-16 05:28:09 -04:00
lwvmobile
f229f0d648 Testing Simpler P25 1/2 Decoder and Heuristics; 2023-09-15 10:30:49 -04:00
lwvmobile
cbaed9337b Fix Compiler Error on RTL Dev Enum; 2023-09-13 13:19:05 -04:00
lwvmobile
66ff2551e9 Add RTL Device Enum and SN support to Ncurses; 2023-09-13 11:09:01 -04:00
lwvmobile
0a7e86a8fa Add RTL Device Enum and SN support to CLI; 2023-09-13 11:05:28 -04:00
lwvmobile
e3c96f2d5d Fix OSS 48k1 Slot On/Off Toggle; 2023-09-12 18:36:00 -04:00
lwvmobile
24741ed420 Update Version Number for PC Aero AW Build; 2023-09-12 18:28:17 -04:00
lwvmobile
1f6f8f194b DMR - Tweak to CSBK (BTV_GRANT) and FLC (BTV); 2023-09-12 17:14:43 -04:00
lwvmobile
102966482b DMR - Add T3 Multi Item Data Call Grants; Tweaks; 2023-09-12 16:38:36 -04:00
lwvmobile
eb7929e758 DMR T3 -- Add P_MAINT Decode; 2023-09-12 15:59:05 -04:00
lwvmobile
8bbfdf2671 Tweaks to DMR LE for mismatching key/alg; 2023-09-12 00:23:41 -04:00
lwvmobile
958400eaf6 DMR C_AHOY and Special Address Identifiers; 2023-09-11 23:28:31 -04:00
lwvmobile
20e862a6a0 Fix Line Break Issue on DMR SLC Err; 2023-09-11 09:13:39 -04:00
lwvmobile
8cbb30b036 DMR T3 Tweak to TG and SRC Values when Tuning; 2023-09-10 21:15:56 -04:00
lwvmobile
9696042156 Fix Keyring Loader to allow KeyID of 0 (P25); 2023-09-10 21:01:16 -04:00
lwvmobile
56b27dd055 Fix NXDN Ncurses Call TG:0 History Bug; 2023-09-09 20:47:48 -04:00
lwvmobile
a388e9ad85 Enable TG Hold Tests on DMR Cap+, Con+, XPT; #132 2023-09-09 20:12:40 -04:00
lwvmobile
2e93cca73a Test Trunk P_CLEAR return to CC on DMR T3; #132 2023-09-09 19:50:07 -04:00
lwvmobile
6a694444c5 Test TG Trunking Hold on DMR T3 Systems; #132; 2023-09-09 19:48:25 -04:00
lwvmobile
8227b49b59 Tweak DMR T3 Channel Numbering Information; 2023-09-08 19:41:32 -04:00
lwvmobile
dd483c3300 Init Group Mode Str; Tweak Group List Conditions; 2023-09-07 12:02:32 -04:00
lwvmobile
f217f17c52 Fix EDACS AFS Reporting on PV Console Output; 2023-09-06 19:03:44 -04:00
lwvmobile
be3f69a2d0 Raw Signal Wav File Saving; #163 2023-09-04 22:17:46 -04:00
lwvmobile
bf96b96fdf Fix Indent; 2023-09-04 19:28:33 -04:00
lwvmobile
c7537cca96 EDACS Analog Call Dotting Sequence Detection; 2023-09-04 17:20:42 -04:00
lwvmobile
14a87465ce Fix/Tweak EDACS Dotting Sequence; 2023-09-04 15:42:28 -04:00
lwvmobile
8c8df5b1b4 EDACS Dotting Sequence FS Detection and CC Jump; 2023-09-04 01:47:22 -04:00
lwvmobile
a56c736c06 ENC Audio Mute Checkdowns; Misc; 2023-08-28 09:21:28 -04:00
lwvmobile
7ff3e3e79b Disable Test Alert on Ncurses Startup for OSS; 2023-08-27 16:29:07 -04:00
lwvmobile
c5713c52da AW Version Update; 2023-08-27 14:59:26 -04:00
lwvmobile
5bea494193 Disable DMR MS/Simplex When Trunking Enabled; 2023-08-26 21:21:28 -04:00
lwvmobile
e48b715f4f DMR SB TXI Tweaks; Add CRC4 Check to LE MI; 2023-08-26 17:19:53 -04:00
lwvmobile
12ac9460b9 DMR LE Minor Code Fix; Print Tweaks; 2023-08-26 09:30:53 -04:00
lwvmobile
c8c72eadab Fix M17 IV; 2023-08-25 09:15:47 -04:00
lwvmobile
cd476bb463 Fix M17 Enc Type Values; 2023-08-25 09:11:18 -04:00
lwvmobile
53617bd366 Fix EDACS Analog Call Preemption Conditions; 2023-08-22 09:16:28 -04:00
lwvmobile
99f2606d4d UDP Audio Output -- Fix Typo; 2023-08-22 09:07:56 -04:00
lwvmobile
2aebdf79f3 UDP Audio Output -- Socket Code, Example Tweaks; 2023-08-22 09:04:47 -04:00
lwvmobile
c840544d25 UDP Audio Output -- Clarify and Add Example; 2023-08-21 17:40:28 -04:00
lwvmobile
927df66e9a Fix Warning; 2023-08-21 16:12:16 -04:00
lwvmobile
7f4443c77f UDP Audio Output -- Old Audio Handler Fix; 2023-08-21 15:54:03 -04:00
lwvmobile
1600e6c0d4 UDP Audio Output -- Audio Implementation; 2023-08-21 15:23:03 -04:00
lwvmobile
0c86ba29fc UDP Audio Output -- Initial Setup; 2023-08-21 15:20:53 -04:00
lwvmobile
b2f6b158e3 Disable RTL RMS Function on ARM Devices (RPi); 2023-08-19 20:48:34 -04:00
lwvmobile
6ab2f69111 Temp Fix for EDACS Standard/Networked; 2023-08-19 12:47:01 -04:00
lwvmobile
0097942732 DMR increase BF and block storage; R1 Pad Bit Fix; 2023-08-19 10:04:09 -04:00
lwvmobile
3686e7fdd2 DMR 3/4 Simple Error Correction; 2023-08-19 07:21:25 -04:00
lwvmobile
0e8f3362b9 P25p2 I-ISCH/DUID Error Correction; 2023-08-17 13:42:35 -04:00
lwvmobile
078142bd3f Misc; 2023-08-17 05:14:07 -04:00
lwvmobile
304817b68e Create Some Temp Files For Code Organization; 2023-08-17 04:53:35 -04:00
lwvmobile
e48c05a0ab AGF Tests/Tweaks; 2023-08-13 11:34:08 -04:00
lwvmobile
4cdcefb980 Analog Monitor Hold on SQL Break; Misc; 2023-08-13 11:30:21 -04:00
lwvmobile
dcc818e9c3 More NCurses Cosmetic Tweaks/Type Fix; 2023-08-11 20:17:40 -04:00
lwvmobile
0037064958 Ncurses Cosmetic Tweaks; 2023-08-11 20:08:08 -04:00
lwvmobile
c0ccbf73d0 More Cygwin M17 Related Bandaids; 2023-08-11 15:18:37 -04:00
lwvmobile
500d0387fd Prevent Possible Overflow in lbuf and lbuf2; 2023-08-11 15:15:47 -04:00
lwvmobile
0f077832cf Update Install Notes and Include Arch Installer; 2023-08-11 12:58:22 -04:00
lwvmobile
449468f566 Fix Some NXDN Array Sizes and Chainbacks; 2023-08-11 12:13:16 -04:00
lwvmobile
fd2444f2cd M17 Misc Cleanup; 2023-08-11 10:56:26 -04:00
lwvmobile
d6968dffdd Misc Code Cleanup; 2023-08-10 13:57:50 -04:00
lwvmobile
b50119e0bc Simplify DMR Trellis Decoder; 2023-08-10 03:43:37 -04:00
lwvmobile
58e90298eb Add M17 CAN Value to Ncurses; Misc; 2023-08-09 20:55:29 -04:00
lwvmobile
224dc1e68c Allow OSS Audio Source Monitoring when 48k1; 2023-08-09 03:58:10 -04:00
lwvmobile
e9262f18db Fix RTL Source Audio Monitoring Bug; 2023-08-09 03:37:54 -04:00
lwvmobile
14b4af8b33 WIP: Working Analog/Raw Source Audio Monitoring; 2023-08-08 22:52:32 -04:00
lwvmobile
af271f62f3 Analog RMS Compiler Warning Fix; 2023-08-08 01:12:45 -04:00
lwvmobile
6f9fba9fbf EDACS Tweaks to Analog Call Handling; 2023-08-08 00:46:20 -04:00
lwvmobile
afa329b5e4 Experimental EDACS Analog Voice Monitoring; 2023-08-07 04:55:58 -04:00
lwvmobile
d8395fff59 Fix RTL RMS so it does't return Jank Values; 2023-08-07 04:32:01 -04:00
lwvmobile
81abd65da1 Fix Some DateName Issues for dates in Aero; 2023-08-07 04:29:41 -04:00
lwvmobile
a48c197ecc Update Example_Usage for Icecast; #159 2023-08-07 04:28:49 -04:00
lwvmobile
85d53896de Update Example_Usage.md 2023-08-07 04:27:21 -04:00
lwvmobile
8b844aa6e3 Disable Float Mono Audio Decimation; 2023-08-04 23:14:00 -04:00
lwvmobile
578117d82a Add patch files to gitignore; 2023-08-04 19:11:24 -04:00
lwvmobile
363c99ceca Fix Float Baseline; Notes on P25p2 Audio; 2023-08-04 18:46:49 -04:00
lwvmobile
a93177eb61 Ncurses Terminal Minor Cleanup and Term Tweaks; 2023-08-04 17:07:40 -04:00
lwvmobile
d6181e2dcd P25 Fix Some Logic Regarding Symbol Rate Switch; 2023-08-04 17:07:18 -04:00
lwvmobile
f9b74cf7e2 More Tweaking on AGF and Float Audio; 2023-08-03 15:38:44 -04:00
lwvmobile
d4740550e4 Fix Bug w/ Manual Gain in Ncurses; 2023-08-03 10:43:57 -04:00
lwvmobile
d91c44f6f3 Doc and Ncurses Cleanup; 2023-08-02 23:03:40 -04:00
lwvmobile
e59b46448a More Work/Tweaks on AGF and Ncurses Gain Control; 2023-08-02 22:48:17 -04:00
lwvmobile
d826391d16 Ncurses and Misc Tweaks; 2023-08-02 17:17:15 -04:00
lwvmobile
5406960f26 Fix Warning and Clarify Short/Float Manual Gain; 2023-08-02 16:42:13 -04:00
lwvmobile
8f1d1e4934 Tweaks to AGF function; Misc; 2023-08-02 14:35:10 -04:00
lwvmobile
54b6fd67e7 Change Defaults; Reorder Ncurses Menu; Fix X2; 2023-08-01 16:03:38 -04:00
lwvmobile
1568ee6176 Random Alignment Fixes; 2023-07-31 20:01:11 -04:00
lwvmobile
6978ac9cd3 DSTAR Fix CRC on Slow Data Header; Cleanup; 2023-07-31 19:50:12 -04:00
lwvmobile
1961eb832a DSTAR Slow Data Decoding WIP; 2023-07-31 16:50:25 -04:00
lwvmobile
c38423c251 DMR Stereo Tweak; Clear Stale Audio Buffers; 2023-07-30 13:41:25 -04:00
lwvmobile
ecd3ec1c61 Fix VoiceFS4 Slot On/Off Issue; 2023-07-29 22:02:03 -04:00
lwvmobile
66e8bcd86a Audio Mono Audio to Stereo Channel Tweaks; 2023-07-29 21:48:28 -04:00
lwvmobile
23b1036c6b Rewrite and Simplify DSTAR Handling; 2023-07-29 21:46:11 -04:00
lwvmobile
0d4ab17d0a Reorganize MBE handling -- initial commit; 2023-07-29 21:43:53 -04:00
lwvmobile
b38a692fc5 Rewrite Call Alert; Switch to Generated Tone; 2023-07-29 21:16:02 -04:00
lwvmobile
2ff96a6b91 Version Update; 2023-07-29 00:16:38 -04:00
lwvmobile
9089d6568a Cleanup; 2023-07-29 00:14:33 -04:00
lwvmobile
73c43b030e Rename XDMA to AUTO; Disable Legacy Auto; 2023-07-29 00:02:17 -04:00
lwvmobile
42fa737844 Configure OSS Output to be more Dynamic; 2023-07-28 23:32:17 -04:00
lwvmobile
e4f61115c6 M17 Cleanup and M17/Aero Jank Fixes; 2023-07-28 23:22:13 -04:00
lwvmobile
3bb9994589 Tweak Toggle Voice Synthesis for FDMA Sources; 2023-07-28 20:53:56 -04:00
lwvmobile
23f6c75257 Ncurses Tweak for TDMA Slot ON/OFF; 2023-07-28 19:26:53 -04:00
lwvmobile
3bac7ba99b Round of Code Cleanup; 2023-07-28 17:47:33 -04:00
lwvmobile
56a5df86a0 Fix Some Slot Preference Clashes; 2023-07-28 17:25:16 -04:00
lwvmobile
50d707a8e3 Rewrite OSS Handling (depending on use case); 2023-07-28 16:06:58 -04:00
lwvmobile
aa49e5869b User Enable/Disable Slots for Voice; 2023-07-28 15:56:06 -04:00
lwvmobile
d982a2b91e Temp Commit WIP; 2023-07-26 15:53:55 -04:00
lwvmobile
a92736bb3a Fix dPMR, pV, and MBEplayback for new audio; 2023-07-26 15:06:33 -04:00
lwvmobile
54386285cc Tweaks to DMR MS Audio Handling; 2023-07-26 15:04:02 -04:00
lwvmobile
676027a56f Tweak Float Auto Gain; Make User Configurable; 2023-07-26 07:21:25 -04:00
lwvmobile
cdc0d9e012 Tweak Install Notes; 2023-07-25 18:54:13 -04:00
lwvmobile
32d4c0ed72 AGF by Left/Right Channel/Slot; 2023-07-25 13:10:19 -04:00
lwvmobile
16959cac7a WIP: audio_work 2; 2023-07-24 18:32:09 -04:00
lwvmobile
f2f20f8f94 Fix P25p2 SACCH PDU Issue; 2023-07-22 18:34:54 -04:00
lwvmobile
1a8efd5835 YSF Decoded Wav File Saving on V/D2 Voice; 2023-07-20 10:12:17 -04:00
lwvmobile
5a01c7a4db Version; 2023-07-20 00:32:54 -04:00
lwvmobile
1b18139e41 Custom User Wav File with -7 option; 2023-07-20 00:32:44 -04:00
lwvmobile
263b3bbeda Fix Some Tab Alignment in dsd_main.c; 2023-07-13 13:59:21 -04:00
lwvmobile
cba01aaa59 Add Exitflag to DMR BS Loop; Update Readme; 2023-07-13 13:57:55 -04:00
lwvmobile
d4599b05a0 Appease Volo - God of Compiler Warnings; 2023-07-10 20:09:42 -04:00
lwvmobile
200287316d Fix Random Warnings on #152 2023-07-10 19:25:14 -04:00
lwvmobile
1d05f3d851 M17 More Work and Fixes; #152 2023-07-10 19:25:06 -04:00
lwvmobile
8e8d987686 NXDN LZ Tweak on RCCH Disc; #123 2023-07-10 19:24:54 -04:00
lwvmobile
343512e9bf Fix OSS Input/Output on M17 8K Sample; #152 2023-07-09 00:13:12 -04:00
lwvmobile
af612c058b M17 Dbuf Temp Bug Fix; Misc; #152 2023-07-09 00:13:01 -04:00
lwvmobile
d81e8be3cf Fix Cmake for Codec2 in Cygwin; #152 2023-07-09 00:12:49 -04:00
lwvmobile
fb93289538 Fix M17 3200bps Voice; Misc M17 Tweaks; #152 2023-07-07 02:17:50 -04:00
lwvmobile
92a2217e80 M17 Support (Partially Working Now); 2023-07-06 21:58:24 -04:00
lwvmobile
b6d41260e7 M17 Initial Support (Non-Working State); 2023-07-06 21:55:13 -04:00
lwvmobile
bb6b54990f Ncurses NXDN RAN/History Lazy Bug Fix; 2023-07-05 16:24:39 -04:00
lwvmobile
016d27e22d Minor Ncurses Fixes; 2023-07-05 14:38:06 -04:00
lwvmobile
17a336e27d Misc Minor Fixes; 2023-07-05 14:33:43 -04:00
lwvmobile
c3f3573a99 Merge pull request #151 from volo-zyko/fix-emptyBodyAndPointerSignWarnings
Fix warnings from -Wempty-body, -Wunused-label, and -Wpointer-sign
2023-07-05 13:58:44 -04:00
Volo Zyko
81dab2f0b6 Fix warnings from -Wempty-body, -Wunused-label, and -Wpointer-sign 2023-07-04 12:07:30 +03:00
lwvmobile
a80e534179 DMR LE ENC Identifiers Tweak; 2023-07-03 12:41:55 -04:00
lwvmobile
8310f87504 Merge pull request #150 from volo-zyko/fix-unusedParameterWarnings
Fix more warnings, now with unused parameters
2023-07-03 12:25:28 -04:00
lwvmobile
f27057c790 Merge pull request #148 from volo-zyko/ZDev3
Set exitflag before cleaning up
2023-07-03 12:25:17 -04:00
Volo Zyko
649d267fa5 Fix more warnings, now with unused parameters 2023-07-03 15:37:43 +03:00
Volo Zyko
d8a7e5d366 Set exitflag before cleaning up
This will signal to all related code that the program
is about to exit.
2023-07-03 11:03:51 +03:00
lwvmobile
8ccc241743 Fix Compiler error: parameter name omitted; 2023-07-02 15:42:32 -04:00
lwvmobile
af922d209d Fix ysf.c Unused Variables Warnings; 2023-07-01 22:59:32 -04:00
lwvmobile
958d0debbb Fix Trellis.c Unused Variables Warnings; 2023-07-01 22:59:13 -04:00
lwvmobile
2016891bd5 Fix NXDN de-scrambling bug; 2023-07-01 22:21:20 -04:00
lwvmobile
412cb26c0f Fix Ncurses Exitflag; 2023-07-01 22:06:49 -04:00
lwvmobile
3fc983f273 Add YSF to default decoding class; #143 2023-07-01 18:51:00 -04:00
lwvmobile
b5d24f9c00 Merge pull request #147 from volo-zyko/fix-unusedVariableWarning
Fix warnings related to unused variables
2023-07-01 13:27:49 -04:00
Volo Zyko
a432173cd6 Fix warnings related to unused variables 2023-07-01 13:48:38 +03:00
lwvmobile
5440161ff9 YSF Fix CM Variable; Line Break; #146 2023-06-30 18:43:32 -04:00
lwvmobile
bb542c475c YSF Radio ID Mode; Element Tweaks; #143 2023-06-30 16:48:43 -04:00
lwvmobile
aef834e914 Fix Line #137 2023-06-30 11:00:23 -04:00
lwvmobile
fd44120874 Merge pull request #145 from volo-zyko/fix-cleanupAndExit
Add signal handlers for a proper cleanup
2023-06-30 10:53:14 -04:00
Volo Zyko
0e9b2b245d Add signal handlers for a proper cleanup
Fix locking problem in get_rtlsdr_sample when it waits indefinitely
even when exitflag is non-zero; cleanup the code.
2023-06-30 14:12:48 +03:00
lwvmobile
eacbd21c50 Refine/Fix YSF FICH Element Decode #143 2023-06-30 01:15:05 -04:00
lwvmobile
deca8e74a8 Fix YSF Full Rate Voice #143 2023-06-29 22:55:22 -04:00
lwvmobile
9eefbb26d8 Fix Code Tab Alignment #143 2023-06-29 18:16:48 -04:00
lwvmobile
b637462ee8 WIP: YSF Decoding; #143 2023-06-29 18:07:43 -04:00
lwvmobile
7fc513e09e Symbolbin Display Fix in Ncurses; #138 2023-06-29 16:01:18 -04:00
lwvmobile
802e1c96bd Merge pull request #142 from volo-zyko/cleanup-symbolOutFileAPI
Cleanup symbol out file api
2023-06-29 15:45:04 -04:00
Volo Zyko
0bc75f6f78 Cleanup code related to symbol out (logic did not change) 2023-06-29 18:51:58 +03:00
lwvmobile
32a3ba535b Merge pull request #141 from lwvmobile/main
upstream
2023-06-29 10:37:22 -04:00
lwvmobile
2e898d997b Merge pull request #139 from volo-zyko/main
Fix potential issues in closeSymbolOutFile
2023-06-29 09:45:51 -04:00
Volo Zyko
817b335349 Fix potential issues in closeSymbolOutFile 2023-06-29 16:21:39 +03:00
lwvmobile
e9d551f4cb Fix Exitflag Variable #136 2023-06-28 16:54:59 -04:00
lwvmobile
33933e914e DMR LE/CAP+/Misc Tweaks; 2023-06-28 16:53:36 -04:00
lwvmobile
8e230a08b5 Misc; 2023-06-20 04:15:51 -04:00
lwvmobile
dfc4f6f304 TXI FLC and Misc; 2023-06-19 10:01:22 -04:00
lwvmobile
5a3061f942 Merge pull request #134 from lwvmobile/zDEV
Zdev Updates
2023-06-19 06:42:26 -04:00
lwvmobile
b40281fda3 Renable DMR Late Entry SB; Misc; 2023-06-19 06:40:21 -04:00
lwvmobile
966fbf8c6a Fix Alignment 3; 2023-06-18 20:15:12 -04:00
lwvmobile
ca65f1b209 Fix Alignment 2; 2023-06-18 20:12:37 -04:00
lwvmobile
a5d73f06d2 DMR - SB TXI Information and ENC Identifiers Fix; 2023-06-18 19:54:18 -04:00
lwvmobile
56b0e8440e Initialize/Zero Some Arrays; 2023-06-17 17:32:59 -04:00
lwvmobile
b6a12b6ceb Fix RC4 'Pop' on DMR when VC6 is Null; Fix Align; 2023-06-17 17:29:03 -04:00
lwvmobile
15a12acfd3 Update Cmake for zDEV; 2023-06-15 17:47:58 -04:00
lwvmobile
c534e0f1fe Merge pull request #133 from lwvmobile/zDEV
Updates;
2023-06-15 17:39:51 -04:00
lwvmobile
5e68580fa6 DMR - Minor Cosmetic Tweaks; 2023-06-15 17:35:42 -04:00
lwvmobile
e6d83e7305 Fix CMake Options error; Update Readme; 2023-06-15 17:29:33 -04:00
lwvmobile
d56cf106b4 DMR Late Entry ENC Fix; Switch to User Option; 2023-06-12 12:38:32 -04:00
lwvmobile
4279ccf292 DMR Anytone RC4 Fix; 2023-06-12 12:35:32 -04:00
lwvmobile
846b202192 Fix P25p1 -f1 Unmute on RC4 Key; Misc; 2023-06-11 19:43:49 -04:00
lwvmobile
330ebe2bf3 Fix Aero OSS Slot Preemption Issues; #127 2023-06-11 03:09:32 -04:00
lwvmobile
79b4a5e720 Fix DMR LE Alg/Key on SB; 2023-06-11 02:22:41 -04:00
lwvmobile
8186b62a91 RC4 Support (DMR, P25p1, P25p2); 2023-06-11 00:11:55 -04:00
lwvmobile
20f0c852aa NXDN Frame Print Tweaks; #123 2023-06-07 18:27:41 -04:00
lwvmobile
9e4ae23c0b Lit Fix and Tones Fix; #127 2023-06-06 20:32:09 -04:00
lwvmobile
585f6f2fa5 Staging for Main Branch #127 Lit Update; 2023-06-06 20:15:34 -04:00
lwvmobile
a4fba3b19c More Codeset Consolidation #127 Location of tones; 2023-06-06 19:53:30 -04:00
lwvmobile
a2180eb5d3 Switch to New NXDN FS (again) #123 2023-06-06 19:01:37 -04:00
lwvmobile
514161fefa NXDN Frame Tweaks; Late Nite FS Testing III; #123 2023-06-05 23:23:32 -04:00
lwvmobile
bba059f35f Late Nite FS Testing II; #123 2023-06-05 03:29:06 -04:00
lwvmobile
5977f865e3 Remove Min/Max Test (mixed results); #123 2023-06-05 02:43:37 -04:00
lwvmobile
ade7c0477f Late Nite FS Testing; #123 2023-06-05 02:17:38 -04:00
lwvmobile
a2fded8340 Revert Change to new NXDN FS; #123 2023-06-04 20:41:16 -04:00
lwvmobile
005e15c45f cmake remove 'zdev' #127 2023-06-04 18:56:41 -04:00
lwvmobile
e9962a8923 NXDN Switch to New FS; Payload Tweaks; #123 2023-06-04 18:45:05 -04:00
lwvmobile
c6611eae9c Update Some Documentation; 2023-06-03 03:55:43 -04:00
lwvmobile
261193959c Restore Documentation and Examples; 2023-06-02 19:21:25 -04:00
lwvmobile
e7a71eabb6 Minor Fix to Call String; 2023-06-02 16:42:38 -04:00
lwvmobile
afba84e584 Cap+ Call String Blink Fix; Minor Tweaks; #125 2023-05-30 14:52:44 -04:00
lwvmobile
96faff7711 RTL Verbosity Tweaks and Thread Safety; #125 2023-05-24 09:17:50 -04:00
lwvmobile
94166b493c Misc; #123 #125; 2023-05-23 06:21:58 -04:00
lwvmobile
6a0b1b2dcf RTL/NCURSES - Clear Queue and Dibit Buffer; #125 2023-05-21 20:19:56 -04:00
lwvmobile
5c8e3d95a7 Ncurses Tweaks; Revert RTL BW changes; #125 2023-05-21 13:39:49 -04:00
lwvmobile
4c91588af6 Re-enable P1 Heuristics On TCH and Non CS modes; 2023-05-21 09:14:02 -04:00
lwvmobile
35c05654a5 Fix NXDN/Scanner Bug; 2023-05-19 19:03:20 -04:00
lwvmobile
fbc9b5fab8 Reverting a few minor RTL tweaks; #125 2023-05-19 18:10:12 -04:00
lwvmobile
1126ab6578 P25 - Allow P2 6000sps on C4FM and QPSK; 2023-05-19 17:39:39 -04:00
lwvmobile
0842613b24 RTL - RMS based soft squelch and tweaks; #125 2023-05-19 11:27:13 -04:00
lwvmobile
bf4a4b574c RTL Misc; Disable Offset and Double BW; #125 2023-05-19 06:42:55 -04:00
lwvmobile
380657679e More LZ Tweaks; #123 2023-05-18 18:55:14 -04:00
lwvmobile
0a214af29b RTL ifdef tag additions; #125 2023-05-18 18:47:16 -04:00
lwvmobile
b008122149 More RTL Tweaks; #125 2023-05-18 10:22:05 -04:00
lwvmobile
7b6feb9e4f Attempt Fix/Clean on RTL input code; #125 2023-05-18 09:29:44 -04:00
lwvmobile
e4861bf94c Fix Idas Trunking Issue; #115 2023-05-17 16:23:22 -04:00
lwvmobile
587a3f01a2 Lima Zulu Tweaks III; #123 2023-05-17 07:37:28 -04:00
lwvmobile
8d5c82356e Initial Main/Aero Code Consolidation; #127 2023-05-15 15:06:34 -04:00
lwvmobile
df039ab1c1 Denny's Cap+ 0x90 Data Flag; #116 2023-05-15 12:14:50 -04:00
lwvmobile
f5e3c6eddd DMR Cap+ Block Counter Fix; #126 2023-05-15 03:00:21 -04:00
lwvmobile
fc01712132 Tweaks to NXDN FSW Tests II; #123 2023-05-14 13:59:29 -04:00
lwvmobile
7ec0bf83b4 Ncurses No Color Trunking Tweaks; #114 2023-05-13 20:11:39 -04:00
lwvmobile
504476c5db Misc Tweaks and Clear Stale Active Ch Values; #120 2023-05-13 01:39:16 -04:00
lwvmobile
f78dbd57bc Fix LimaZulu NXDN Tweaks #123 2023-05-12 02:44:18 -04:00
lwvmobile
d2b27fdf25 Tweaks to NXDN FSW Tests; #123 2023-05-05 18:32:06 -04:00
lwvmobile
3aa20f82b9 pV Conventional Frame Sync and pV Tweaks; #122 2023-05-05 06:34:42 -04:00
lwvmobile
402b2f0264 NXDN Frame Sync Tests and Cmake Option #123 2023-05-05 06:15:03 -04:00
lwvmobile
4dd2328e10 Various uint64_t/ul/ulli fixes for 32-bit; 2023-05-04 23:58:47 -04:00
lwvmobile
98bcdd203e Misc Tweaks and Fixes; 2023-05-03 23:45:04 -04:00
lwvmobile
741ed51d08 NCURSES Active Ch Display Tweaks; #120 2023-05-02 18:34:33 -04:00
lwvmobile
5d8e07228e DMR Active Channel Display; CSBK Tweaks; #120 2023-05-02 18:32:01 -04:00
lwvmobile
4a43a48b2e P25 ENC Trunk Toggle and Active Tweaks; #120 #121 2023-05-02 18:25:28 -04:00
lwvmobile
0ef3b4ab4b Active Channel Display NXDN Setup and Misc; #120 2023-05-02 18:20:51 -04:00
lwvmobile
00e0f00974 NXDN Tweaks to clear stale key values on keyload; 2023-04-29 17:02:55 -04:00
lwvmobile
91181f9e93 TCP Audio Retry on Disc; Ncurses Key '8'; #119 2023-04-29 16:06:41 -04:00
lwvmobile
5c42c50a40 Version Naming Update; 2023-04-25 17:18:35 -04:00
lwvmobile
36399386c5 More NXDN/IDAS Tweaks and Fixes; #115 and #118 2023-04-25 16:00:16 -04:00
lwvmobile
8eee4cd699 NXDN Type-D Decoding/Trunking; NXDN Tweaks; #115 2023-04-23 19:52:36 -04:00
lwvmobile
1410e8bd81 Cap Plus Expansion; Minor DMR Tweaks; #116 2023-04-23 19:50:06 -04:00
lwvmobile
915375fb1c Initial NXDN Type D - 'IDAS' Support; #115 2023-04-13 18:20:58 -04:00
lwvmobile
52fff28dc4 NXDN Array Expansion and Message Tweaks; #113 2023-04-13 11:00:37 -04:00
lwvmobile
bd035622b8 No Color Cmake Build Option #114 2023-04-13 11:00:00 -04:00
lwvmobile
44163710f9 More XPT Work; #110 2023-04-12 18:12:10 -04:00
lwvmobile
44b1ccdeae Hashed DMR TG Multi Key Loading Fix; #112 2023-04-12 13:10:13 -04:00
lwvmobile
34113cb782 housekeeping; 2023-04-09 14:30:05 -04:00
lwvmobile
2a336a9275 Hytera XPT WIP #110 2023-04-08 19:15:33 -04:00
lwvmobile
5c08a9193c Yet Another Cmake Warning Fix #107 2023-03-28 23:33:20 -04:00
lwvmobile
2cae7f9c18 NXDN -- DFA Base Freq Fix; ADJ_SITE_INFO; #106 2023-03-28 17:30:02 -04:00
lwvmobile
e056c97d9d Issue #105 - Make Work with Named Pipe (FIFO) 2023-03-22 20:07:02 -04:00
lwvmobile
dc49e0d08b NXDN DFA Support; 2023-03-22 20:00:41 -04:00
lwvmobile
b639f6af28 Fix Cmake Warnings; 2023-03-21 22:42:09 -04:00
lwvmobile
6b45c4ba9b Issue #105 Segfault Bugfix; 2023-03-21 21:09:45 -04:00
lwvmobile
2062502a59 P2 - TDMA-CC Tuning Bugfix and callstring tweak; 2023-03-21 20:58:44 -04:00
lwvmobile
a490d9ead2 Merge pull request #104 from lwvmobile/lite
NXDN48/96 Tweak;
2023-03-12 15:55:12 -04:00
lwvmobile
c73832ac2c NXDN48/96 Tweak; 2023-03-12 15:42:49 -04:00
lwvmobile
fe1fa79f70 More XPT Tweaks and Notes; 2023-03-09 19:12:57 -05:00
lwvmobile
f2f29f2287 Line Space OCD; 2023-03-09 18:40:36 -05:00
lwvmobile
3181e58b19 Lite to Aero Rebrand; 2023-03-08 02:25:51 -05:00
lwvmobile
6204aec2a5 P25 P1 LCW re-write and updates; 2023-03-08 02:25:29 -05:00
lwvmobile
267180ed0e NCurses LO Return to CC; 2023-03-08 02:04:56 -05:00
lwvmobile
8d9cbb3720 XPT Trunking Tweak; 2023-03-08 02:04:09 -05:00
lwvmobile
8af6d2e185 P25 P1 QPSK MSIZE/SSIZE Tweak; 2023-03-08 02:03:01 -05:00
lwvmobile
abeb92ff8a Fix trunk_hangtime lf to f; Ncurses Fixes; 2023-03-06 03:07:27 -05:00
lwvmobile
be47075611 Fix Fast Scanner and NCurses Display (again) 2023-03-05 05:54:23 -05:00
lwvmobile
1640b58ae4 Fix unintended bug in iden_up_vu; 2023-03-04 20:54:52 -05:00
lwvmobile
7a34d531b1 Literature Update 2023-03-04 19:28:58 -05:00
lwvmobile
0af814c72f P25 TSBK PDU Fix; vPDU PDU Fixes; Scanner Freq Fix 2023-03-04 19:26:44 -05:00
lwvmobile
1477190dea Fast Scan Ncurses Tweak; Update Literature; 2023-03-03 15:38:39 -05:00
lwvmobile
b0cd1881bb P25 - P1 MBF Format Addition; TSBK/vPDU Tweaks; 2023-03-03 15:15:42 -05:00
lwvmobile
44ad75ec17 NXDN Trunking Tweaks and Misc Tweaks; 2023-03-02 22:13:49 -05:00
lwvmobile
1ce487dc13 Trunking -- Faster CC Hunt; 2023-03-01 18:32:29 -05:00
lwvmobile
ed9a96fdc8 Experimental -- Fast Scanner Feature; 2023-03-01 17:56:10 -05:00
lwvmobile
c677efda49 P25 - Remove Test Code; NXDN - Remove Freq Calc; 2023-03-01 17:49:52 -05:00
lwvmobile
fea4f97b89 DMR - XPT Tweaks; Data Header Tweaks; 2023-02-25 16:08:55 -05:00
lwvmobile
f2e3834e0a FID 0x10 - FLCO 0x14, 0x15, 0x16, 0x17, 0x18; 2023-02-24 20:51:47 -05:00
lwvmobile
b8b62ef69a Disable remaining setmod_bw as safety precaution; 2023-02-24 20:46:33 -05:00
lwvmobile
4a8a4a088a NXDN Trunking Tweak - Snap Back to CC on Disc; 2023-02-24 18:41:02 -05:00
lwvmobile
9308c5b251 Fix P_Protect CSBK GI indicator; 2023-02-24 18:39:56 -05:00
lwvmobile
cdfe9435d3 Fix NCurses **tera key display when loaded; 2023-02-24 18:39:01 -05:00
lwvmobile
f6cd915f4d Misc Tweaks; Multi BP; More CapMax FLCO; XPT; 2023-02-23 21:59:08 -05:00
lwvmobile
1dfd59801e Literature Update; 2023-02-22 20:00:24 -05:00
lwvmobile
c4513fab7a NXDN Tweaks and SACCH/FACCH CRC Fixes; 2023-02-22 19:46:06 -05:00
lwvmobile
a3b8839897 Minor Cap+ and XPT Fix; 2023-02-21 13:55:15 -05:00
lwvmobile
9e009867ff Disable/Tweak some setmod_bw defaults; 2023-02-20 17:59:53 -05:00
lwvmobile
e95e2218d9 Cap+ NL; Hytera XPT Trunk Support (experimental) 2023-02-20 12:47:30 -05:00
lwvmobile
a9742043b8 General DMR Tweaks; 64-bit IV from 32-bit MI; 2023-02-20 12:43:16 -05:00
lwvmobile
05eef039c9 DMR - LRRP tweaks; Add LOCN PDU. 2023-02-20 12:41:20 -05:00
lwvmobile
818e952b7b DMR - dheader rewrite; UDT/USBD fix; block tweaks; 2023-02-20 12:40:42 -05:00
lwvmobile
38b962aacf P25 Dibit, Block and PDU Payload Tweaks; 2023-02-20 12:35:44 -05:00
lwvmobile
0217202801 DMR - Fix Cap+ CSBK; Various Minor Fixes; 2023-02-05 16:47:58 -05:00
lwvmobile
ef07b48540 DMR Minor Code Fixes; 2023-02-04 20:10:38 -05:00
lwvmobile
db67a8b227 NCurses Compiler Warning and Call Alert Fix; 2023-02-04 04:35:06 -05:00
lwvmobile
4e2c4577d5 DMR Cap+ CSBK Improvements; 2023-02-03 22:15:13 -05:00
lwvmobile
e581c96560 DMR FLCO Tweaks; P25 Site/RFSS Display; 2023-02-02 20:03:52 -05:00
lwvmobile
f3505269d0 DMR Conf Data CRC9; Message CRC32; Tweaks; 2023-02-01 05:35:21 -05:00
lwvmobile
20ccdbbced DMR FLC Tweaks; CSBK Cleaning; 2023-02-01 05:31:40 -05:00
lwvmobile
fc2fb99502 P25P2 OSS Bugfix; 2023-01-29 18:41:03 -05:00
lwvmobile
143c560958 DMR FLCO - Check PF First; 2023-01-29 16:09:47 -05:00
lwvmobile
d122d7e935 DMR Unknown FLCO Tweaks; PI Tweaks; 2023-01-28 21:00:13 -05:00
lwvmobile
d0f9bb4bad Fix DMR FEC/CRC/RAS Implementation Issues; 2023-01-21 05:43:42 -05:00
lwvmobile
ac752029bd Tweak RAS/CRC; Other Misc Tweaks; 2023-01-19 09:42:42 -05:00
lwvmobile
5b994f5129 NXDN Multi-Key CSV Import; Example Updt; 2023-01-18 12:18:56 -05:00
lwvmobile
ec7d7c24a5 DMR SB/RC Additions; Cap+ LC/CSBK; RAS; 2023-01-17 23:58:52 -05:00
lwvmobile
1d49481f2d Fix/Restore MBEout Files; 'DSP' CACH; Tweaks; 2023-01-17 02:25:53 -05:00
lwvmobile
7ca8cb421c Cap+ FLC/CSBK Tweaks; 2023-01-17 02:08:25 -05:00
lwvmobile
4eb44b3c67 'DSP' File Output for OKDMR - Initial Commit; 2023-01-15 22:04:04 -05:00
lwvmobile
e16e4b61fc Cap+ Things; 2023-01-15 21:22:28 -05:00
lwvmobile
fbd04fa869 Allow Standard BP Key on MBE File Playback; 2023-01-15 18:13:48 -05:00
lwvmobile
7f9b852f36 Fix Audio Gain/Device Out on MBE File Playback; 2023-01-15 18:12:15 -05:00
lwvmobile
f5a7ab2b77 P25 P2 ISCH Var Fix; 2023-01-15 18:09:47 -05:00
lwvmobile
ffe6098fb8 DMR Cap+ Rest Channel FLCO/SLCO Fix; 2023-01-09 19:39:05 -05:00
lwvmobile
157ca8c043 RTL Input Tuning Fix (UDP); Minor Tweaks; 2023-01-09 14:13:00 -05:00
lwvmobile
b722e43a3a dPMR Scrambler Key Support; 2023-01-07 18:41:44 -05:00
lwvmobile
2ba9953d33 'Lite' Optimizations and Tweaks for Win32CYG Build 2023-01-05 18:38:12 -05:00
lwvmobile
bb2199ee84 Con+ CSBK and Tuning Fixes; Group Call Options; 2023-01-02 08:04:22 -05:00
lwvmobile
4efec4e4ef Capacity Plus 'Things'; CSBK PF Check; 2022-12-30 07:22:30 -05:00
lwvmobile
12cf9aa80f Ncurses Call Toggle; T3 Call Safeguard; Lit Updt; 2022-12-29 10:06:15 -05:00
lwvmobile
e5a42dbb11 Literature Update; Minor Tweaks; CSBK update; 2022-12-28 08:43:00 -05:00
lwvmobile
67eaeadc03 Update Readme; 2022-12-27 11:27:03 -05:00
lwvmobile
acb5c16c30 Update README.md 2022-12-27 10:25:40 -05:00
lwvmobile
d16e775e46 Update README.md 2022-12-27 09:23:57 -05:00
lwvmobile
11d4c8c49c More Staging; 2022-12-27 09:18:07 -05:00
lwvmobile
1477880720 Staging for Promotion to Master Branch; 2022-12-27 08:32:34 -05:00
lwvmobile
9290098081 TCP/RIG Err Handling; Ncurses Menu Entries; 2022-12-27 07:04:49 -05:00
lwvmobile
eeb6924369 Default Smoothing Off; Upsample 8k Audio to 48k; 2022-12-26 09:37:37 -05:00
lwvmobile
c02d7c0ba0 DMR Trunking VC/CC Sync Time Tweaks; 2022-12-26 08:44:13 -05:00
lwvmobile
324191d79f Disable Audio Smoothing TCP/RTL; Make User Toggle; 2022-12-23 18:27:13 -05:00
lwvmobile
e613b85829 Lockout TG Audio Playback and Keyboard Shortcuts; 2022-12-21 22:02:13 -05:00
lwvmobile
49f81da4df Trunking White List, Private and Data Calls; 2022-12-21 21:20:57 -05:00
lwvmobile
826c99d563 Minor CSBK/CC Freq Tweak; Literature Tweak; 2022-12-20 21:15:37 -05:00
lwvmobile
2441664b19 RIGCTL hostname to mirror TCP Audio Link Hostname; 2022-12-19 18:24:37 -05:00
lwvmobile
5c733c0660 Remus Ncurses Call String Stuff; 2022-12-19 05:30:48 -05:00
lwvmobile
73824084ad Overcook DMRLA and T3 Site ID Things; 2022-12-19 04:59:00 -05:00
lwvmobile
209d4e039e DMR Con+ Site Id Bugfix/Revert; 2022-12-18 23:23:23 -05:00
lwvmobile
fa4e84bc77 DMR LRRP and T3 Site Id Work; 2022-12-18 21:52:59 -05:00
lwvmobile
4946897914 Minor DMR Trunk/Site Tweaks; Update Readme w demo; 2022-12-17 23:39:45 -05:00
lwvmobile
57e3f518dd DMR T3 DX Calls; RTL Input Frequency Check; 2022-12-15 19:22:54 -05:00
lwvmobile
08a548339c LRRP and Caputre Bin CLI Switches L and c; 2022-12-15 03:09:27 -05:00
lwvmobile
36c337ede8 Update Readme and Example Files; 2022-12-15 01:41:43 -05:00
lwvmobile
f6bb325dac DMR RTL Trunking Code Fix; 2022-12-14 18:06:50 -05:00
lwvmobile
626869992e DMR Con+ VC Sync Time Fix; SetMod_BW Fix; 2022-12-14 17:12:21 -05:00
lwvmobile
5422b337bb RTL work; Reassign CLI Switches; Fix CTRL+C; 2022-12-14 16:21:30 -05:00
lwvmobile
b6f270be05 NXDN Check for CC Freq Tweak; 2022-12-14 13:09:26 -05:00
lwvmobile
3ea813ebbc DMR Trunking VC Hangtime Tweaks; TG Block Tweak; 2022-12-14 00:04:36 -05:00
lwvmobile
53980c98ed DMR Con+ VC Hangtime Tweaks; 2022-12-13 20:20:28 -05:00
lwvmobile
536372d877 Set CC Frequency from RIGCTL if not specified; 2022-12-12 21:30:18 -05:00
lwvmobile
896f3a8533 User Configurable TCP Audio and SetMod BW; 2022-12-12 08:32:41 -05:00
lwvmobile
68bbea64d5 P25 Yellow PDUs; 2022-12-12 08:31:54 -05:00
lwvmobile
711a4cb871 More DMR Trunking Tweaks; MFID tweaks; 2022-12-11 16:33:25 -05:00
lwvmobile
8fd1d8fe35 DMR T3 Tweak; DMR Voice Tweak; Ncurses Reset Fix; 2022-12-10 20:35:14 -05:00
lwvmobile
23c396cbe8 DMR Cap+ Trunking RC Increment Reversion; 2022-12-09 23:41:10 -05:00
lwvmobile
e91c21fadb Fix Hangtime/CC Return Bug; 2022-12-09 22:39:37 -05:00
lwvmobile
15a8f80344 Assign Chan Map Import to LCN Freq for CC Hunting; 2022-12-09 18:23:20 -05:00
lwvmobile
5130899a67 DMR Con+ and Cap+ Trunking Fixes; 2022-12-09 18:03:53 -05:00
lwvmobile
f5ac9ff0b2 LRRP Temp Disable Most Reporting Types; 2022-12-09 18:02:15 -05:00
lwvmobile
14dd045312 Remus; 2022-12-09 08:36:42 -05:00
lwvmobile
fbb00f78fe Roman NCurses EGPS/LRRP/Data Display Fix; 2022-12-08 12:35:34 -05:00
lwvmobile
a5d23d9e12 MBC Header and Blocks CRC; 2022-12-07 22:58:57 -05:00
lwvmobile
a2b3da5b5a NCurses LRRP Tweak and Roman Data Header Stuff; 2022-12-07 18:00:09 -05:00
lwvmobile
a9417afd67 DMR EGPS, LRRP, Data Block Tweaks; 2022-12-07 04:26:11 -05:00
lwvmobile
438f89bf4c Add Date to Per Call Time Stamp; 2022-12-07 02:06:26 -05:00
lwvmobile
2f2eecddfc Various Trunking Tweaks; 2022-12-06 08:47:46 -05:00
lwvmobile
2fceee5a2f Reverse Mute 2022-12-04 19:15:33 -05:00
lwvmobile
62c70cbf92 Update Readme and Images; 2022-12-04 18:40:49 -05:00
lwvmobile
b97014ff0b DMR Cap+ Trunk Logic 2022-12-04 17:10:19 -05:00
lwvmobile
68edb9463c DMR NCurses Tweaks and Additions; E-GPS; 2022-12-04 14:35:26 -05:00
lwvmobile
178f88a28f DMR Reorganization; Initial Trunking Support; 2022-12-03 20:16:43 -05:00
lwvmobile
f7d103c6a2 NXDN Sync Type Tweak; 2022-12-03 17:08:01 -05:00
lwvmobile
10d10063f0 Additional Trunking Checkdown; 2022-12-02 18:45:25 -05:00
lwvmobile
dba3b79266 Disable Debug Frame Sync Prints; 2022-11-28 15:20:44 -05:00
lwvmobile
0441b8fdbd Hangtime Safety Parenthesis 2022-11-28 09:23:56 -05:00
lwvmobile
ea399e50a8 NXDN Preamble + FSW Sync; 2022-11-24 18:43:51 -05:00
lwvmobile
66f710e877 Channel to Frequency Map CSV Importer; 2022-11-23 09:08:32 -05:00
lwvmobile
0f227e40c3 Remove Unused OP25 NXDN Trellis Decoder; 2022-11-23 08:59:56 -05:00
lwvmobile
136ed75342 NCurses Display Group Labels in P25 and DMR; Tweak 2022-11-20 07:31:02 -05:00
lwvmobile
61cefa6a87 Trunking Hangtime and Tweaks; NXDN F2U Tweak; 2022-11-19 19:43:48 -05:00
lwvmobile
cc7504c280 Route /dev/dsp and pa input/output to pulse; 2022-11-18 11:06:42 -05:00
lwvmobile
07139b3d7d P25p2 QPSK Optimization Tweaks; 2022-11-18 09:44:53 -05:00
lwvmobile
638f212525 Update Readme and Screenshots; Keyboard Shortcuts; 2022-11-17 11:23:10 -05:00
lwvmobile
9f624e0b62 NXDN CAC/CCH Messages; Initial Trunking Support; 2022-11-17 05:50:14 -05:00
lwvmobile
eefe1bac5e Minor Cleanup and Tweaks; 2022-11-16 17:00:26 -05:00
lwvmobile
532c1cc3b6 P25 Trunking Additions; 2022-11-16 16:10:37 -05:00
lwvmobile
b1c40ed6e7 Roman DMR End Call Alert 2022-11-13 23:35:17 -05:00
lwvmobile
94dbd1512d P25 Trunking Initial Commit; 2022-11-13 23:04:50 -05:00
lwvmobile
c73d45d553 EDACS tweaks; 2022-11-12 03:34:21 -05:00
lwvmobile
d1efa05164 NXDN Permissed Data Conditional Check; 2022-11-11 22:45:33 -05:00
lwvmobile
7af5ffe9fa NXDN FSW and Lich Based Decoding; 2022-11-11 22:12:37 -05:00
lwvmobile
8141ea2e78 T_Max Frame Sync Work; Reorganizing; 2022-11-11 22:07:37 -05:00
lwvmobile
ec4ace1514 EDACS; Init Tr; RIGCTL; TCP and WAV in; 2022-11-09 23:51:58 -05:00
lwvmobile
eb5cbaad93 DEV BUILD designation 2022-11-09 15:32:45 -05:00
lwvmobile
f5d0575978 Update README.md 2022-11-06 00:39:34 -04:00
lwvmobile
a0d9e349c2 TSBK NET_STS_BCST Last Block Fix; Protect Block; 2022-11-02 01:40:45 -04:00
lwvmobile
7ca65cf687 Call History Fix & Timestamp; Cap+ VLC Fix; 2022-11-01 03:54:10 -04:00
lwvmobile
b4a0e2e9f3 P2 4V/2V Deinterleave Fix; Errs now C0 and C1; 2022-10-25 19:21:57 -04:00
lwvmobile
73f0d5df44 P25 TSBK Bug Fix; Add More P25 PDUs; 2022-10-23 21:36:06 -04:00
lwvmobile
b003d0a210 Merge pull request #90 from KuzVlad/fix_lfsr
fixed function signature
2022-10-23 15:20:45 -04:00
KuzVlad
83f390ba88 fixed function signature 2022-10-23 13:13:05 +03:00
lwvmobile
c8aafb1be0 P25 P2 Frame Stabilization and Tweaks 2022-10-22 18:45:25 -04:00
132 changed files with 45472 additions and 17386 deletions

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
*.[ao]
*.so*
*.dylib
build
*.sh
*.csv
examples
*.bin
*.ans
*.patch
*.zip
result

View File

@@ -1,11 +1,52 @@
#Ubuntu 20.04 uses 3.16.3
#Ubuntu 22.04 uses 3.22.1
#Arch currently on 3.26.3
#Cygwin currently using 3.23.2 (or newer)
cmake_minimum_required(VERSION 3.10.2)
project(dsd-fme) project(dsd-fme)
cmake_minimum_required(VERSION 2.8.11)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
#Set curses to ncurses, and wide true for ascii #Set curses to ncurses, and wide true for ascii
set(CURSES_NEED_NCURSES TRUE) set(CURSES_NEED_NCURSES TRUE)
set(CURSES_NEED_WIDE TRUE) set(CURSES_NEED_WIDE TRUE)
#use cmake option -DAERO=ON to enable Aero Builds (OSS support and specific tweaks)
option(AERO
"Build for Aero Environments (Cygwin)" OFF)
if (AERO)
add_definitions(-DAERO_BUILD)
endif ()
#use cmake option -DCOLORS=OFF to disable color output
option(COLORS
"Build with Colors Enabled" ON)
if (COLORS)
add_definitions(-DPRETTY_COLORS)
endif ()
#use cmake option -DPVC=ON to enable Provoice Conventional Frame Sync
option(PVC
"Build with Provoice Conventional Frame Sync Enabled" OFF)
if (PVC)
add_definitions(-DPVCONVENTIONAL)
endif ()
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
option(LZ
"Build with new LimaZulu Requested NXDN Tweaks Enabled" OFF)
if (LZ)
add_definitions(-DLIMAZULUTWEAKS)
endif ()
#use cmake option -DSID=ON to enable P25p1 Soft ID decoding -- Experimental
option(SID
"Build with P25p1 LSD/Soft ID Enabled" OFF)
if (SID)
add_definitions(-DSOFTID)
endif ()
include(git_revision) include(git_revision)
git_describe(GIT_TAG) git_describe(GIT_TAG)
@@ -14,10 +55,11 @@ find_package(MBE REQUIRED)
find_package(ITPP REQUIRED) find_package(ITPP REQUIRED)
find_package(RTLSDR) find_package(RTLSDR)
find_package(Curses REQUIRED) find_package(Curses REQUIRED)
find_package(PULSEAUDIO REQUIRED) find_package(PulseAudio REQUIRED)
find_package(CODEC2)
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}) include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${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) if(RTLSDR_FOUND)
find_package(Threads) find_package(Threads)
@@ -26,6 +68,12 @@ if(RTLSDR_FOUND)
add_definitions(-DUSE_RTLSDR) add_definitions(-DUSE_RTLSDR)
endif(RTLSDR_FOUND) endif(RTLSDR_FOUND)
if(CODEC2_FOUND)
include_directories(SYSTEM ${CODEC2_INCLUDE_DIRS})
list(APPEND LIBS ${CODEC2_LIBRARIES})
add_definitions(-DUSE_CODEC2)
endif(CODEC2_FOUND)
FILE(GLOB SRCS src/*.c src/*.cpp) FILE(GLOB SRCS src/*.c src/*.cpp)
FILE(GLOB HEADERS include/*.h include/*.hpp) FILE(GLOB HEADERS include/*.h include/*.hpp)
@@ -41,6 +89,11 @@ include_directories("${PROJECT_SOURCE_DIR}/include")
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS}) ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS}) TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>
-Wmisleading-indentation -Wparentheses -Wunused-value -Wreturn-type
-Wtautological-compare)
include(GNUInstallDirs) include(GNUInstallDirs)
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@@ -27,3 +27,7 @@ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 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 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
# Digital Speech Decoder - Florida Man Edition
This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/dsd "szechyjs") RTL branch and some of my own additions, along with portions of DMR and NXDN code from the [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve") branch. This code also borrows snippets, inspiration, and ideas from other open source works including [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25"), [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"). This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu and hrh17 for the many hours of wav samples submitted by them.

250
README.md
View File

@@ -1,251 +1,18 @@
# Digital Speech Decoder - Florida Man Edition # Digital Speech Decoder - Florida Man Edition
This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/dsd "szechyjs") RTL branch and some of my own additions, along with portions of DMR and NXDN code from the [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve") branch. This code also borrows snippets, inspiration, and ideas from other open source works including [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25"), [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"). This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu and hrh17 for the many hours of wav samples submitted by them. 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.
## 2022.10.01 Update ## 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.
Very Experimental (Mostly Just Sampling Speed and using built in QPSK demodulator) for Phase 2 CQPSK 6000 sps input over disc tap inputs (SDR++, GQRX, WAV files). Promising results, but some errors in decoding as expected. I've had some pretty good luck using SDR++ to listen to and decode Duke Energy TDMA Control Channel through the virtual sink. Experimental CQPSK can be toggled in Ncurses Menu and also via command line switch `-f2 -m2` but keep in mind this will only work with Phase 2 RF channels using CQPSK, and not a combined decoding. ![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/audio_work/dsd-fme2.png)
Also, added some new iden_up PDUs and other odd and end P25 PDU's (still far from complete). Ncurses Terminal and Console output will now show relevant frequencies for CC and Voice channels if iden_up commands are present. ![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/audio_work/dsd-fme3.png)
DSD-FME, and The Florida Man Labs will be taking a hiatus period from straigth development of this project. Currently, I feel we are at a bit of a stand still as far as what can be done with the project without new demodulation, dibit buffer, audio, and input methods. DSD-FME will continue to receive maintenance updates for simple bug fixes and also any major bug issues that cause crashing, etc., but I am reluctant to continue developing with the current underlying issues mentioned above. I am going to go into a period of hiatus with this project and do lots of experimentation, learning, and testing to see what viable options are out there or need to be created from scratch. I feel like I've learned a lot, achieved a lot, made tons of mistakes, learned from a few of them, but ultimately improved on the DSD project. DSD-FME will continue to receive replies and support in any opened issues but will currently only extend to help in setting up and using the software, on top of regular minor maintenance and any crash related issues. ## Information
## 2022.09.28 Mini Update ##
Back by popular demand, I've re-implemented DMR Stereo as a standalone decoder. DMR Stereo is also still available in XDMA decoding for P25 1, 2, and DMR BS/MS Simplex as well.
DMR Stereo `dsd-fme -fs`
XDMA `dsd-fme -ft`
It can also be selected in the NCurses Terminal Menu. Sadly I had to remove the X2-TDMA decoder option in the menu, I'm sure nobody will miss it.
## 2022.09.17 Update ##
P25 Phase 2 Audio decoding has been implemented into DSD-FME. Currently, Phase 2 will only work from OP25 symbol capture bin files, or from wav files/SDR applications/RTL input that are sourced from FSK4 sources. CQPSK (LSM/H-D8PSK) will not work from audio sources. With the addition of Phases 2 audio, a new default decoder class has been implemented, XDMA, which is P25 Phase 1, Phase 2, DMR BS and MS (DMR Stereo). Furthermore, very limited Phase 1 TSBK support and Phase 2 FACCH/SACCH/LCCH has been worked in just to get Network Status Broadcasts, which can fill in the required P2 parameters for WACN, SYSID, and CC for Phase 2 frame de-scrambling, and active voice call information.
With the implementation of the XDMA decoder class (default decoder), the CLI switches for DMR Stereo has been repurposed. -T option will now open a per call wav file saving when used with NCurses Terminal, otherwise it will write wav files to slot 1 and slot 2 wav files.
Anybody using `dsd-fme -fr -T` ...... should now just use `dsd-fme -ft` instead!
To see the up to date CLI options, please look at the help options with the -h CLI option.
## 2022.08.12 Update ##
A new menu system has been introduced in the NCURSES Terminal. Also includes support for LRRP to text file type of choice and reading OP25 symbol capture bin files.
[![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme.png)](https://www.youtube.com/watch?v=TqTfAfaPJ4s "DSD-FME Update 2022.08.12")
To get started with the new menu system, simply launch with:
`dsd-fme -N 2> log.txt`
## 2022.06.20 Update - Current Users Please Read!! ##
The executable for this project has been changed from `dsd` to `dsd-fme` so after pulling or cloning the lastest version, make sure to call the software with `dsd-fme`.
## 2022.05.05 Update ##
DMR Stereo method added for listening to voice audio in both TDMA channels/slots simultaneously.
### Example Usage and Note!
`dsd-fme` or `./dsd-fme` may need to be used in your usage, depending on if you are running it from the build folder, or if you have run make install. You will need to tweak the examples to your particular usage. Users can always check `dsd-fme -h` for help and all command line switches to use.
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, P25 (1 and 2) and X2-TDMA decoding. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
```
-ft XDMA decoder class (P25 1 and 2, DMR BS/MS, X2-TDMA)
-fs DMR Stereo BS/MS Simplex
-fa Legacy Auto
-fi NXDN48
-fn NXDN96
-fp ProVoice
-fm dPMR, also may need to use -xd if inverted dPMR.
-fr DMR, also may need to use -xr if inverted DMR.
-f1 P25P1
-fx X2-TDMA
```
## Example Usage - New XDMA Decoder, Ncurses Terminal, Pulse Input/Output, and Log Console to file
`dsd-fme -ft -N 2> voice.log`
and in a second terminal tab, same folder, run
`tail -n 40 -f voice.log`
Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently)
## Example Usage - RTL2832 Dongle Input
`dsd-fme -fi -i rtl -c 154.9875M -P -2 -D 1 -G 36 -L 70 -U 6021 -Y 12`
```
-i rtl to use rtl_fm (default is -i pulse for pulse audio)
-o pulse to set output to pulse audio (excluded, is default anyways)
-c Set frequency
-P set PPM error (default = 0)
-D set device index number (default = 0; first device detected)
-G set device gain (0-49) (default = 0 Auto Gain)
-L set rtl squelch to 70 (default = 0; off)
-U set UDP port for rtl_fm remote control (default = 6020)
-Y 12 set rtl VFO bandwidth in kHz, (default = 12)(6, 8, 12, 16, 24, 48)
```
## Example STDIN UDP from GQRX or SDR++, output to Pulse Audio, and append decoded audio to wav file
Be sure to first start UDP output sink in GQRX or SDR++ and set VFO appropriately
`socat stdio udp-listen:7355 | dsd-fme -fi -i - -w nxdn.wav`
## Example Usage - Extra Information for Academic Study and Logging
`dsd-fme -Z -N 2>> voice.log`
and in a second terminal tab, same folder, run
`tail -n 40 -f voice.log`
![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme2.png)
## Roadmap
The Current list of objectives include:
1. New demodulators and input method(s) (considering liquid-dsp).
2. Graphical User Interface (may need to migrate to new project).
3. Lots of experimentation.
## How to clone, check out, and build this branch
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 22.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
```
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/pulseaudio/download-and-install.sh
chmod +x download-and-install.sh
./download-and-install.sh
```
If you have dependencies already installed (i.e. need a fresh clean install on a system with DSD-FME already or using system other than Debian/Ubuntu, etc), please run this instead:
```
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/pulseaudio/download-and-install-nodeps.sh
chmod +x download-and-install-nodeps.sh
./download-and-install-nodeps.sh
```
### Ubuntu 18.04/LM19/Buster Note:
The above install.sh should now function on older system types. You can elect to manually follow the steps down below. Do NOT Manually build and install ITPP 4.3.1 on older systems, it is currently not wanting to build on Ubuntu 18.04 and Linux Mint 19. Install it from the repository instead.
## Manual Install
First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different.
```
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
```
## Headless
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
```
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio
```
### Build and Install ITPP - ONLY IF NOT IN REPO!!
```
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
tar xjf itpp*
#if you can't cd into this folder, double check folder name first
cd itpp-4.3.1
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
```
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice") This version of MBELib is 1.3.1 and prints to STDERR, using the stock 1.3.0 MBElib may cause problems with print alignments if paired with this version of DSD-FME, or cause issues with printing over the screen in future builds.
```
git clone https://github.com/lwvmobile/mbelib
cd mbelib
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
```
Finish by running these steps to clone and build DSD-FME w/ pulseaudio support.
```
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
git branch -a
git checkout remotes/origin/pulseaudio
git checkout -b pulseaudio
git branch -a #double check to see if you are on pulseaudio branch
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
mkdir build
cd build
cmake ..
make -j `nproc`
##only run make install if you don't have another version already installed##
sudo make install
sudo ldconfig
```
Optional 'Virtual Sinks' for routing audio from SDR++ or GQRX, Media Players, etc. into DSD-FME
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired.
```
pacmd load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
pacmd load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
```
Already have this branch, and just want to pull the latest build? You can run the rebuild.sh file in the dsd-fme folder, or manually do the pull with the commands:
```
##Open your clone folder##
git pull https://github.com/lwvmobile/dsd-fme pulseaudio
##cd into your build folder##
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
```
If the call alert wav files aren't playing, then make sure to run the following in the dsd-fme folder to copy the wav files to the /usr/share/ folder and give them adequate permission to be accessed.
```
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
```
# Join the Conversation
Want to help drive the direction of this project and read more about the latest updates and releases to DSD-FME? Then join the conversation on the 'unofficial official' [DSD-FME](https://forums.radioreference.com/threads/dsd-fme.438137/ "DSD-FME") Forum Thread on the Radio Reference Forums.
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/audio_work/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/trunking.sh "trunking examples").
## License ## License
Copyright (C) 2010 DSD Author Copyright (C) 2010 DSD Author
@@ -262,3 +29,4 @@ GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 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 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.

31
cmake/FindCODEC2.cmake Normal file
View File

@@ -0,0 +1,31 @@
# - Try to find CODEC2
# Once done this will define
#Seems to work on Cygwin as well now -- more testing for may be required
# Not sure what causes the 'Package 'codec2', required by 'virtual:world', not found' message, but seems to work anyways
# -- Checking for module 'codec2'
# -- Package 'codec2', required by 'virtual:world', not found
# -- Found CODEC2: /usr/local/lib/libcodec2.dll.a
if (NOT CODEC2_FOUND)
find_package(PkgConfig)
pkg_check_modules(CODEC2_PKG codec2)
set(CODEC2_DEFINITIONS ${PC_CODEC2_CFLAGS_OTHER})
find_path(CODEC2_INCLUDE_DIR
NAMES codec2/codec2.h codec2.h
HINTS ${CODEC2_PKG_INCLUDE_DIRS})
find_library(CODEC2_LIBRARY
NAMES codec2/codec2 codec2
HINTS ${CODEC2_PKG_LIBRARY_DIRS})
set(CODEC2_LIBRARIES ${CODEC2_LIBRARY})
set(CODEC2_INCLUDE_DIRS ${CODEC2_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CODEC2 DEFAULT_MSG CODEC2_LIBRARY CODEC2_INCLUDE_DIR)
mark_as_advanced(CODEC2_INCLUDE_DIR CODEC2_LIBRARY)
endif (NOT CODEC2_FOUND)

View File

@@ -0,0 +1,52 @@
#! /bin/bash
#
cdir=$(pwd)
clear
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer For Arch Linux\n
This will install the required packages, clone, build, and install DSD-FME only.
This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.\n
MBELib is considered a requirement on this build.
You must view the Patent Notice prior to continuing.
The Patent Notice can be found at the site below.
https://github.com/lwvmobile/mbelib#readme
Please confirm that you have viewed the patent notice by entering y below.\n\n"
read -p "Have you viewed the patent notice? y/N " ANSWER
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
if [ "$ANSWER" = "y" ]; then
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
git clone https://github.com/lwvmobile/mbelib
cd mbelib
git checkout ambe_tones
mkdir build
cd build
cmake ..
make -j $(nproc)
sudo make install
sudo ldconfig
sudo cp /usr/local/lib/libmbe.so /usr/lib/libmbe.so
cd $cdir
git clone https://github.com/lwvmobile/dsd-fme
### For branch audio_work - git clone --branch audio_work https://github.com/lwvmobile/dsd-fme
cd dsd-fme
#git checkout audio_work
mkdir build
cd build
cmake ..
make -j $(nproc)
sudo make install
sudo ldconfig
printf "Any issues, Please report to either:\nhttps://github.com/lwvmobile/dsd-fme/issues or\nhttps://forums.radioreference.com/threads/dsd-fme.438137/\n\n"
else
printf "Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.\n\n"
fi

View File

@@ -1,26 +1,17 @@
#! /bin/bash #! /bin/bash
clear clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer printf "\nDigital Speech Decoder: Florida Man Edition - Auto Installer\n
echo This will clone, build, and install DSD-FME only. This will clone, build, and install DSD-FME only.
echo If you need dependencies installed, please run download-and-install.sh instead. If DSD-FME has never been installed on this machine,
echo then you will need to install the dependencies first!
Please run download-and-install.sh instead.\n\n"
read -p "Press enter to continue" read -p "Press Enter to continue..." x
git clone https://github.com/lwvmobile/dsd-fme git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme cd dsd-fme
git branch -a #git checkout audio_work
git checkout remotes/origin/pulseaudio
git checkout -b pulseaudio
git branch -a #double check to see if you are on pulseaudio branch
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
mkdir build mkdir build
cd build cd build
cmake .. cmake ..
make -j `nproc` make -j $(nproc)
##only run make install if you don't have another version already installed##
sudo make install sudo make install
sudo ldconfig sudo ldconfig

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

View File

@@ -1,70 +1,44 @@
#! /bin/bash #! /bin/bash
#
cdir=$(pwd)
clear clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer printf "Digital Speech Decoder: Florida Man Edition - Auto Installer\n
echo MBELib is considered a requirement on this build. MBELib is considered a requirement on this build.
echo You must view this notice prior to continuing. You must view the Patent Notice prior to continuing.
echo The Patent Notice can be found at the site below. The Patent Notice can be found at the site below.
echo https://github.com/lwvmobile/mbelib#readme https://github.com/lwvmobile/mbelib#readme
echo Please confirm that you have viewed the patent notice by entering y below. Please confirm that you have viewed the patent notice by entering y below:\n\n"
echo read -p "Have you viewed the patent notice? y/N " ANSWER
echo y/N ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
read ANSWER if [ "$ANSWER" = "y" ]; then
Y='y' sudo apt update
if [[ $Y == $ANSWER ]]; then sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
chkitpp=$(sudo apt list libitpp-dev 2>&1|grep -ci "installed")
sudo apt update if [ "$chkitpp" -lt "1" ];then
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 printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
read -p "Press Enter to exit..." x
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu. exit 1
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo. fi
read -p "Press enter to continue" git clone https://github.com/lwvmobile/mbelib
cd mbelib
#wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files git checkout ambe_tones
#tar xjf itpp* mkdir build
#if you can't cd into this folder, double check folder name first cd build
#cd itpp-4.3.1 cmake ..
#mkdir build make -j $(nproc)
#cd build sudo make install
#cmake .. sudo ldconfig
#make -j `nproc` cd $cdir
#sudo make install git clone https://github.com/lwvmobile/dsd-fme
#sudo ldconfig cd dsd-fme
#cd .. #git checkout audio_work
#cd .. mkdir build
cd build
git clone https://github.com/lwvmobile/mbelib cmake ..
cd mbelib make -j $(nproc)
mkdir build sudo make install
cd build sudo ldconfig
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
git branch -a
git checkout remotes/origin/pulseaudio
git checkout -b pulseaudio
git branch -a #double check to see if you are on pulseaudio branch
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
mkdir build
cd build
cmake ..
make -j `nproc`
##only run make install if you don't have another version already installed##
sudo make install
sudo ldconfig
else else
echo printf "\nSorry, you cannot build DSD-FME without acknowledging the Patent Notice.\nExiting...\n\n"
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice. exit 2
fi fi

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 393 KiB

BIN
dsd-fme3.png Normal file

Binary file not shown.

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

376
examples/Example_Usage.md Normal file
View File

@@ -0,0 +1,376 @@
### 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.
```
-ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
-fs DMR Stereo, also may need to use -xr if inverted DMR
-fa Legacy Auto (not recommended)
-fi NXDN48
-fn NXDN96
-fp 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)
-fx X2-TDMA
-fy YSF
-fz M17 Audio
```
## Conventional Frequency Scanner
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies to attain a frame sync.
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the scan switch. Note: This method will NOT perform at a level similar to a real hardware scanner, SDR tuning is not nearly as fast or reliable at locking onto signal.
To scan through a mixture of DMR and P25 Conventional, use:
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
To scan through NXDN48 only conventional, use:
`dsd-fme -fi -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
To scan through NXDN96 only conventional, use:
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~ Using `-t 0` will forego the one second wait time, and this can work in some situations, but is not advised as it may skip during the middle of transmissions, or skip over them entirely without a framesync.
Please Note: DMR Simplex may not behave well on scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
## Trunking Examples
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
## Example Usage - Default Decoder, Ncurses Terminal, Pulse Input/Output, and Log Console to file
`dsd-fme -N 2> voice.log`
and in a second terminal tab, same folder, run
`tail -n 40 -f voice.log`
### 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 ###
--TCP Direct Audio Link with SDR++
`dsd-fme -i tcp` Currently defaults to localhost:7355 (SDR++ defaults)
`dsd-fme -i tcp:192.168.7.5:7356` (remote host and custom port)
--48000/9600 Mono Wav File Input
`dsd-fme -i filename.wav` 48k/1 Audio (SDR++, GQRX wav recordings)
`dsd-fme -i filename.wav -s 96000` 96k/1 (DSDPlus Raw Signal Wav Files)
Wav File Input Note: Due to 96000 rate audio requiring me to double the symbol rate and center, be sure to use the -s 96000 at the very end of the startup command. Also, some NXDN48/96 may have difficulties decoding properly with wav file input.
## Example Usage - RTL2832 Dongle Input
Short Setup (all default values):
`dsd-fme -i rtl`
Detailed Setup:
`dsd-fme -ft -i rtl:0:154.9875M:26:-2:8:0:6020 `
```
RTL-SDR options:
Usage: rtl:dev:freq:gain:ppm:bw:sq: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)
gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)
ppm <num> RTL-SDR PPM Error (default = 0)
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
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
```
## Example Usage - Extra Payload/PDU Logging
`dsd-fme -Z -N 2> log.ans`
and in a second terminal tab, same folder, run
`tail -n 40 -f log.ans`
### EDACS/P25/NXDN/DMR Simple/Single VFO Trunking ###
EDACS Trunking (w/ channel map import)
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (see switches above for STD/NET, EA, and ESK modes)
`dsd-fme -i tcp -fE -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
--NXDN48 Trunking (Direct Frequency Assignment) with SDR++ (untested for frequency accuracy)
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
--NXDN48 Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 in channel_map.csv)
`dsd-fme -fi -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
--DMR Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 (TIII and Con+) in channel_map.csv)
`dsd-fme -fs -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
--P25 Trunking P1 and P2 (C4FM) with SDR++
`dsd-fme -i tcp -T -U 4532 -N 2> log.ans`
--P25 Trunking (QPSK) with P1 Control Channel (Should switch symbol rate and center on Phase 2 audio channels)
`dsd-fme -i tcp -T -U 4532 -N -mq 2> log.ans`
--P25 Trunking Phase 2 TDMA Control Channel systems with QPSK (non Phase 1 systems)
`dsd-fme -i tcp -T -U 4532 -N -f2 -m2 2> log.ans`
Trunking Note1: All samples above can also be run with the RTL input method and setting of RTL UDP remote port. In terms of performance, however, SDR++ will do a much better job on weaker/marginal signal compared to the RTL input. RTL input should only be used on strong signal.
`dsd-fme -fp -i rtl:0:851.8M:22:-2:24:0:6020 -T -C channel_map.csv -G group.csv -N 2> log.ans`
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus style LSN-esque numbering into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the lpcn (12-bit logical physical channel number - decimal format) values from the log, and not the LPCN+TS (13-bit DSDPlus LSN) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
```
00:43:00 Sync: +DMR [slot1] slot2 | Color Code=00 | CSBK
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
LPCN: 0075; TS: 2; LPCN+TS: 0152; Target: 16518173 - Source: 16533625
```
Use channel 75 in your import file, which would correspond to dsdplus channels 151 and 152 (151 = TS1 / 152 = TS2).
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
Trunking Note4: NXDN Trunking v1 will require a channel map. Please see the example folder for an appropriate channel map. NOTICE: NXDN trunking has been fixed on the RTL (rtl_fm) input method and works correctly now using a soft squelch value to determine when to look for frame sync. Tests show this works very well, but squelch adjustments may be required to differentiate the noise floor from the signal.
NXDN Trunking Update: NXDN DFA (Direct Frequency Assignment) has been coded from the v2 documents, so using a channel map may not be required, as long as the DFA is configured with standard values, and not 'system definable' values. This will only work on trunking systems that use DFA (newer systems) in accordance to the v2 CAI document NXDN TS 1-A Version 2.0 September 2016. If the system uses 'system definable' values, then make sure to put the channels in a channel map csv file as as the 16-bit OFN values for proper tuning.
NXDN Type-D/IDAS Update: Type-D or IDAS decoding/trunking has been coded now and tested on a small two channel system. Set up a channel map much like Type-C trunking. If preferred, insert channel 31 at the top of your channel map for the 'home repeater' or go to channel of choice during a TX_REL or DISC message. Extensive testing of Type-D has not been conducted. Some cavaets may currently include iffy per call wav file saving and potentially shifting SRC and TGT ID values due to how SCCH messages are handled and how Busy Repeater Messages are handled. Private calls will need to be enabled by enabling 'data calls', if desired. During testing, only data calls came on private calls, so this was set to disabled by default, but can be enabled with data calls enabled. Also, note that some home repeater channels may or may not carry calls from all systems.
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.
Hytera XPT: Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file, listing each LSN channel to a frequency (see examples/hytera_xpt_chan.csv). Currently, this set up is working with smaller XPT systems that I have been able to test with.
## NCurses Keyboard Shortcuts ##
Some Keyboard Shortcuts have been implemented for testing to see how users like them. Just hope nobody pushes a key on accident and doesn't know which one it was or what it does. The current list of keyboard shortcuts include:
```
esc or arrow keys - ncurses menu
q - quit
c - toggle compact mode
h - toggle call history
z - toggle console payloads
a - toggle call alert beep
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
6 - force rc4 key assertion over missing pi header/le enc identifiers (dmr)
i - toggle signal inversion on types that can't auto detect (dmr, dpmr)
m - toggle c4fm/qpsk 10/4 (everything but phase 2 signal)
M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
R - start capturing symbol capture bin (date/time name file)
r - stop capturing symbol capture bin
spacebar - replay last symbol capture bin (captures must be stopped first)
s - stop playing symbol capture bin or wav input file (lower s)
P - start per call decoded wav files (Capital P)
p - stop per call decoded wav files (lower p)
t - toggle trunking (needs either rtl input, or rigctl connection)
y - toggle scanner (needs either rtl input, or rigctl connection)
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
2 - Toggle Voice Synthesis in TDMA Slot 2
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
d - Toggle Trunking Tuning to Data Calls (DMR T3, NXDN)
e - Toggle Trunking Tuning to Encrypted Calls (P25)
8 - Connect to SDR++ TCP Audio Sink with Defaults/Retry Sink Connection on Disconnect
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
D - Reset DMR Site Parms/Call Strings, etc.
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
k - Hold TG in Slot 1 or Conventional, or clear current hold
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)
```
## Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
Make sure to enable "Stereo Mix" from Volume Control Panel and then disable Windows Sounds.
```
ffmpeg -f dshow -i audio="Stereo Mix (Realtek High Definition Audio)" -c:a aac -b:a 64k -content_type 'audio/aac' -vn -f adts icecast://source:password@192.168.5.251:8844/DSDFME
```
## Sending Audio to a Icecast 2 Server via FFmpeg (Linux w/ Pulse Audio)
`pactl list short sources`
Choose Desired Device to Cast:
```
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
1 alsa_output.pci-0000_0d_00.3.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
2 alsa_input.pci-0000_0d_00.3.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
3 virtual_sink.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
4 virtual_sink2.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
7 alsa_output.pci-0000_0b_00.1.hdmi-stereo-extra1.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
```
Example:
```
francis@12cores:~$ pactl list short sources
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
francis@12coresx:~$ ffmpeg -f pulse -i 0 -c:a libmp3lame -ab 64k -f mp3 icecast://source:password@XXXXXXXXX:8000
```
Note: Do not run this command for ffmpeg/icecast piped to the main dsd-fme command, make sure these are running in seperate terminals.
## Sending Audio to UDP Target/Port
Audio can be sent to a target address on your local area network with the UDP blaster using the `-o udp:targetaddress:port` option.
Note: Any analog audio monitoring will not function properly over UDP port (rate difference issues)
Example (Short 8k/2):
`dsd-fme -fs -o udp:192.168.7.8:23470`
Receiving End (Short 8k/2):
`socat stdio udp-listen:23470 | play --buffer 640 -q -b 16 -r 8000 -c2 -t s16 -`
Example (Short 8k/1):
`dsd-fme -f1 -o udp:192.168.7.8:23469`
Receiving End (Short 8k/1):
`socat stdio udp-listen:23469 | play --buffer 320 -q -b 16 -r 8000 -c1 -t s16 -`
Example (Float 8k/2):
`dsd-fme -ft -y -o udp:192.168.7.8:23468`
Receiving End (Float 8k/2):
`socat stdio udp-listen:23468 | play --buffer 1280 -q -b 16 -r 8000 -c2 -t f32 -`
Example (Float 8k/1):
`dsd-fme -fi -y -o udp:192.168.7.8:23467`
Receiving End (Float 8k/1):
`socat stdio udp-listen:23467 | play --buffer 640 -q -b 16 -r 8000 -c1 -t f32 -`
Note: --buffer option in play is calculated by (channels * samples * sizeof(samples)),
where samples is 160 for mono, 320 for stereo, and short samples are 2 and float samples are 4.
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
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.

212
examples/Install_Notes.md Normal file
View File

@@ -0,0 +1,212 @@
## How to clone and build this branch
### 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.
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
```
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install.sh
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
sh download-and-install-Arch.sh
```
### Other:
If you have dependencies already installed, please run this instead:
```
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-nodeps.sh
sh download-and-install-nodeps.sh
```
## Manual Install
First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different.
Debian/Mint/Ubuntu/Pi
```
sudo apt update
#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
```
sudo dnf update
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
```
Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/lwvmobile/dsd-fme/issues/153
```
sudo pacman -Syu
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
```
## Headless Ubuntu Server/Pi
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
```
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
```
### Build and Install ITPP - ONLY IF NOT IN REPO!!
```
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
tar xjf itpp*
#if you can't cd into this folder, double check folder name first
cd itpp-4.3.1
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
```
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
```
git clone https://github.com/lwvmobile/mbelib
git checkout ambe_tones
cd mbelib
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
```
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
```
cp libmbe* /usr/lib
cp cygmbe* /usr/lib
cp cygmbe* /bin
```
or
```
sudo cp libmbe* /usr/lib
sudo cp cygmbe* /usr/lib
sudo cp cygmbe* /bin
```
Finish by running these steps to clone and build DSD-FME.
```
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
```
### Windows Cygwin Builds
If using RTL input support, you must install libusb-win32 before proceeding with Cygwin installation. You will also need to build and compile a version of librtlsdr, but this can be tricky, and personally, I had to resort to using a much older version of the source code to get it to build at all with the rtl support in the precompiled 'Aero' builds.
Then install all dependencies available in the repo prior to building, either directly selecting them during setup with the setup-x86.exe or setup-x64.exe or by issuing a command similar to this:
```
setup-x64.exe --packages libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,xfce-pulseaudio-plugin,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,unzip,wget,gcc-g++,libsndfile-devel
```
Then manually install ITPP and MBElib, see above install notes. Be sure to run `cp libmbe* /usr/lib` after compiling MBElib.
Then you can build and install using
```
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
mkdir build
cd build
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
cmake -DAERO=ON ..
make
make install
```
### Virtual Sinks
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input.
```
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
```
Already have this branch, and just want to pull the latest build? You can run the rebuild.sh file in the dsd-fme folder, or manually do the pull with the commands:
```
##Open your clone folder##
git pull
##cd into your build folder##
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
```
### Applying Patches -- Recommended For Advanced Users Only
More experimental or potentially functionality changing or temperamental features may be included as seperate .patch files inside of the patch folder, and are not included in the source code by default.
If users wish to try or use these patches, then they can apply patches and build/rebuild with the following procedure. Make sure you have changed to the dsd-fme directory first, either by the top
command, or by otherwise opening the terminal to the clone folder.
```
cd dsd-fme
git apply patch/patchname.patch
cd build
make
sudo make install
```
If you later wish to update to the latest version via `git pull`, you may first need to reset any patches, perform the `git pull`, and then reapply patches.
A procedure for this is similar to, but not limited to:
```
cd dsd-fme
git reset --hard
git pull
git apply patch/xyz.patch
cd build
make
sudo make install
```
NOTE: Patches can potential break over time with further changes to code, requiring merge resolution or other manual intervention to re-apply patches.

View File

@@ -0,0 +1,10 @@
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
1,858606250
2,858606250
3,859606250
4,859606250
5,860606250
6,860606250
7,861606250
8,861606250
1 LSN(dec) frequency(Hz) (do not delete this line or won't import properly)
2 1 858606250
3 2 858606250
4 3 859606250
5 4 859606250
6 5 860606250
7 6 860606250
8 7 861606250
9 8 861606250

View File

@@ -0,0 +1,19 @@
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
999,862093750,default cc (come here first), optional use non-existent channel as first entry
1,863093750
2,862093750
3,861093750
4,860093750
5,859093750
6,863593750
7,862593750
8,861593750
9,860593750
10,859593750
11,863393750
12,862393750
13,861393750
14,860393750
15,859393750
1 ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
2 999,862093750,default cc (come here first), optional use non-existent channel as first entry
3 1,863093750
4 2,862093750
5 3,861093750
6 4,860093750
7 5,859093750
8 6,863593750
9 7,862593750
10 8,861593750
11 9,860593750
12 10,859593750
13 11,863393750
14 12,862393750
15 13,861393750
16 14,860393750
17 15,859393750

8
examples/dmr_t3_chan.csv Normal file
View File

@@ -0,0 +1,8 @@
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
999,456318750,default cc (come here first), optional use non-existent channel as first entry
36,455756250
54,455981250
81,456318750
1 ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
2 999,456318750,default cc (come here first), optional use non-existent channel as first entry
3 36,455756250
4 54,455981250
5 81,456318750

View File

@@ -0,0 +1,6 @@
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
1,851375000
2,851800000
3,855987500
4,858487500
5,852312500
1 LSN(dec) frequency(Hz) (do not delete this line or won't import properly)
2 1 851375000
3 2 851800000
4 3 855987500
5 4 858487500
6 5 852312500

5
examples/group.csv Normal file
View File

@@ -0,0 +1,5 @@
DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
100,B,Example Name,Tag
1449,A,Fire Dispatch,Fire
929,A,Fire Tac,Fire
22033,DE,Law Dispatch,Law
1 DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
2 100,B,Example Name,Tag
3 1449,A,Fire Dispatch,Fire
4 929,A,Fire Tac,Fire
5 22033,DE,Law Dispatch,Law

View File

@@ -0,0 +1,10 @@
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
1,858606250
2,858606250
3,859606250
4,859606250
5,860606250
6,860606250
7,861606250
8,861606250
1 LSN(dec) frequency(Hz) (do not delete this line or won't import properly)
2 1 858606250
3 2 858606250
4 3 859606250
5 4 859606250
6 5 860606250
7 6 860606250
8 7 861606250
9 8 861606250

6
examples/multi_key.csv Normal file
View File

@@ -0,0 +1,6 @@
key id or tg id (dec), key number or value (dec) //NXDN Scrambler, BP, 10-char Hytera BP only
2,70
1,123
100,70
12,48713912656
672560,254
1 key id or tg id (dec), key number or value (dec) //NXDN Scrambler, BP, 10-char Hytera BP only
2 2,70
3 1,123
4 100,70
5 12,48713912656
6 672560,254

View File

@@ -0,0 +1,5 @@
key id(hex), key value (hex) //10-char Hytera BP, RC4
1,1234567890
2,ABCDEF1234
C,0B57935150
64,0B57935150
1 key id(hex), key value (hex) //10-char Hytera BP, RC4
2 1,1234567890
3 2,ABCDEF1234
4 C,0B57935150
5 64,0B57935150

View File

@@ -0,0 +1,8 @@
channel(dec), freq(Hz)
141,423862500
142,424337500
143,424912500
203,424100000
204,424625000
271,422650000
302,423287500
1 channel(dec) freq(Hz)
2 141 423862500
3 142 424337500
4 143 424912500
5 203 424100000
6 204 424625000
7 271 422650000
8 302 423287500

5
examples/nxdn_sc_key.csv Normal file
View File

@@ -0,0 +1,5 @@
key(dec) or tg(dec), value(dec), load any single keys as key 0
0,23466
1,12345
2,32700
63,32767
1 key(dec) or tg(dec), value(dec), load any single keys as key 0
2 0,23466
3 1,12345
4 2,32700
5 63,32767

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

57
examples/trunking.sh Normal file
View File

@@ -0,0 +1,57 @@
#example trunking sh scripts (SDR++ with RIGCTL and RTL Input)
#make sure to put a # in front of all lines except the one you wish to use
#P25 P1 FDMA CC with C4FM
#dsd-fme -i tcp -U 4532 -T -N 2> log.ans
#dsd-fme -i rtl:0:850M:0:-2:12 -T -N 2> log.ans
#P25 P1 FDMA CC with QPSK (Simulcast)
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
#P25 P2 TDMA CC with C4FM
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -N 2> log.ans
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
#DMR TIII, Con+, Cap+, XPT
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
#EDACS 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
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -C nxdn_channel_map.csv -N 2> log.ans
#NXDN48 Type-C Trunking with DFA
#dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -N 2> log.ans
#NXDN96 Trunking with Channel Map
#dsd-fme -fn -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
#dsd-fme -fn -i rtl -T -C nxdn_channel_map.csv -N 2> log.ans
#Notes: parameters after -i tcp can be omitted if using localhost as the default hostname to connect
#and 7355 as the default port number. -U is the port number for RIGCTL and will mirror the tcp hostname
#running under the assumption that the user will be connnecting the VFO to the same instance of SDR++
#You can also specify an ip address to connect to a remote SDR++ instance, make sure that the settings
#inside of SDR++ match, i.e., change in SDR++ from 'localhost' to an IP to bind to (machine's IP address)
#Note2: RTL input should only be used on strong signal, the SDR++ VFO will perform much better on marginal signal
#paramters after -i rtl can also be omitted now if using the default configurations
#Having a -G group.csv is purely optional, but useful if you want to block groups, or give groups names

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

@@ -52,7 +52,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
state = S2; // lower path state = S2; // lower path
} else { } else {
state = S0; // upper path state = S0; // upper path
}; // end else - if } // end else - if
out[loop]=0; out[loop]=0;
break; break;
@@ -61,7 +61,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
state = S2; // lower path state = S2; // lower path
} else { } else {
state = S0; // upper path state = S0; // upper path
}; // end else - if } // end else - if
out[loop]=1; out[loop]=1;
break; break;
@@ -70,7 +70,7 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
state = S3; // lower path state = S3; // lower path
} else { } else {
state = S1; // upper path state = S1; // upper path
}; // end else - if } // end else - if
out[loop]=0; out[loop]=0;
break; break;
@@ -79,12 +79,12 @@ int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_path
state = S3; // lower path state = S3; // lower path
} else { } else {
state = S1; // upper path state = S1; // upper path
}; // end else - if } // end else - if
out[loop]=1; out[loop]=1;
break; break;
}; // end switch } // end switch
}; // end for } // end for
return(length); return(length);
}; // end function }; // end function

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,7 @@ for (loop=0; loop < size; loop++) {
m_crc = (m_crc >> 8) ^ ccittTab[tmp]; m_crc = (m_crc >> 8) ^ ccittTab[tmp];
}; // end for } // end for
// calculate and save crc-value in fields 54 and 55 of dvframe // calculate and save crc-value in fields 54 and 55 of dvframe
m_crc = ~m_crc; m_crc = ~m_crc;

File diff suppressed because it is too large Load Diff

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* NXDN AMBE interleave schedule
*/
#ifndef _MAIN
extern const int nW[36];
extern const int nX[36];
extern const int nY[36];
extern const int nZ[36];
#else
const int nW[36] = { 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2,
0, 2, 0, 2, 0, 2
};
const int nX[36] = { 23, 10, 22, 9, 21, 8,
20, 7, 19, 6, 18, 5,
17, 4, 16, 3, 15, 2,
14, 1, 13, 0, 12, 10,
11, 9, 10, 8, 9, 7,
8, 6, 7, 5, 6, 4
};
const int nY[36] = { 0, 2, 0, 2, 0, 2,
0, 2, 0, 3, 0, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3
};
const int nZ[36] = { 5, 3, 4, 2, 3, 1,
2, 0, 1, 13, 0, 12,
22, 11, 21, 10, 20, 9,
19, 8, 18, 7, 17, 6,
16, 5, 15, 4, 14, 3,
13, 2, 12, 1, 11, 0
};
#endif

View File

@@ -1,257 +1,82 @@
/* // Portions Below from Osmocom OP25
* Copyright (C) 2010 DSD Author // NXDN Encoder (C) Copyright 2019 Max H. Parke KA1RBI
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) // thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland *
* // OP25 is free software; you can redistribute it and/or modify it
* Permission to use, copy, modify, and/or distribute this software for any // under the terms of the GNU General Public License as published by
* purpose with or without fee is hereby granted, provided that the above // the Free Software Foundation; either version 3, or (at your option)
* copyright notice and this permission notice appear in all copies. // any later version.
* //
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // OP25 is distributed in the hope that it will be useful, but WITHOUT
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // License for more details.
* 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 // You should have received a copy of the GNU General Public License
* PERFORMANCE OF THIS SOFTWARE. // along with OP25; see the file COPYING. If not, write to the Free
*/ // Software Foundation, Inc., 51 Franklin Street, Boston, MA
// 02110-1301, USA.
#ifndef _MAIN static const uint8_t PERM_12_5[] = {
extern const int nW[36]; 0,12,24,36,48,
extern const int nX[36]; 1,13,25,37,49,
extern const int nY[36]; 2,14,26,38,50,
extern const int nZ[36]; 3,15,27,39,51,
extern const char nxdnpr[145]; 4,16,28,40,52,
extern const char nxdnpr2[145]; //why is this 145 but referenced later as 182 or 384 5,17,29,41,53,
//borrow from LEH 6,18,30,42,54,
extern const unsigned char nsW[72]; 7,19,31,43,55,
extern const int DSDNXDN_SACCH_m_Interleave[60]; 8,20,32,44,56,
extern const int DSDNXDN_SACCH_m_PunctureList[12]; 9,21,33,45,57,
extern const int DSDNXDN_FACCH1_m_Interleave[144]; 10,22,34,46,58,
extern const int DSDNXDN_FACCH1_m_PunctureList[48]; 11,23,35,47,59
extern const int DSDNXDN_UDCH_m_Interleave[348];
extern const int DSDNXDN_UDCH_m_PunctureList[58];
//
//enum
//{
#define NXDN_VCALL 0b000001 /* VCALL = VCALL_REQ = VCALL_RESP */
#define NXDN_VCALL_IV 0b000011
#define NXDN_DCALL_HDR 0b001001 /* Header Format - NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
#define NXDN_DCALL_USR 0b001011 /* User Data Format */
#define NXDN_DCALL_ACK 0b001100
#define NXDN_REL_EX 0b000111
#define NXDN_HEAD_DLY 0b001111
#define NXDN_SDCALL_REQ_HDR 0b111000 /* Header Format */
#define NXDN_SDCALL_REQ_USR 0b111001 /* User Data Format */
#define NXDN_SDCALL_RESP 0b111011
#define NXDN_SDCALL_IV 0b111010
#define NXDN_STAT_INQ_REQ 0b110000
#define NXDN_STAT_INQ_RESP 0b110001
#define NXDN_STAT_REQ 0b110010
#define NXDN_STAT_RESP 0b110011
#define NXDN_REM_CON_REQ 0b110100
#define NXDN_REM_CON_RESP 0b110101
#define NXDN_REM_CON_E_REQ 0b110110
#define NXDN_REM_CON_E_RESP 0b110111
//NXDN_VCALL_REQ = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */
//NXDN_VCALL_RESP = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */
#define NXDN_VCALL_REC_REQ = 0b000010 /* NXDN_VCALL_REC_REQ = NXDN_VCALL_REC_RESP */
//NXDN_VCALL_REC_RESP = 0b000010,
#define NXDN_VCALL_CONN_REQ = 0b000011 /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */
//NXDN_VCALL_CONN_RESP = 0b000011, /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */
#define NXDN_VCALL_ASSGN_DUP = 0b000101
//NXDN_DCALL_REQ = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
//NXDN_DCALL_RESP = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */
#define NXDN_DCALL_REC_REQ = 0b001010 /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */
//NXDN_DCALL_REC_RESP = 0b001010, /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */
#define NXDN_DCALL_ASSGN = 0b001110
#define NXDN_DCALL_ASSGN_DUP = 0b001101
#define NXDN_IDLE 0b010000
#define NXDN_DISC_REQ = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
#define NXDN_DISC = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
#else
/*
* pseudorandom bit sequence
*/
const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 };
//const unsigned char nxdnpr2[384] =
const unsigned char nxdnpr2[182] = //generated from default in manual with the x^9+x^4+1 poly?
{
0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0,
1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,
0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1,
0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1,
1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1,
0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,
1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1,
1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
1, 1, 0, 0, 0, 1//, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
// 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0,
// 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
// 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
// 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
// 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0,
// 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1,
// 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1,
// 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
// 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0,
// 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0,
// 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
// 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1
};
/*
* NXDN AMBE interleave schedule
*/
const int nW[36] = { 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2,
0, 2, 0, 2, 0, 2
}; };
const int nX[36] = { 23, 10, 22, 9, 21, 8, static const uint8_t PERM_16_9[] = {
20, 7, 19, 6, 18, 5, 0, 16, 32, 48, 64, 80, 96, 112, 128,
17, 4, 16, 3, 15, 2, 1, 17, 33, 49, 65, 81, 97, 113, 129,
14, 1, 13, 0, 12, 10, 2, 18, 34, 50, 66, 82, 98, 114, 130,
11, 9, 10, 8, 9, 7, 3, 19, 35, 51, 67, 83, 99, 115, 131,
8, 6, 7, 5, 6, 4 4, 20, 36, 52, 68, 84, 100, 116, 132,
5, 21, 37, 53, 69, 85, 101, 117, 133,
6, 22, 38, 54, 70, 86, 102, 118, 134,
7, 23, 39, 55, 71, 87, 103, 119, 135,
8, 24, 40, 56, 72, 88, 104, 120, 136,
9, 25, 41, 57, 73, 89, 105, 121, 137,
10, 26, 42, 58, 74, 90, 106, 122, 138,
11, 27, 43, 59, 75, 91, 107, 123, 139,
12, 28, 44, 60, 76, 92, 108, 124, 140,
13, 29, 45, 61, 77, 93, 109, 125, 141,
14, 30, 46, 62, 78, 94, 110, 126, 142,
15, 31, 47, 63, 79, 95, 111, 127, 143
}; };
const int nY[36] = { 0, 2, 0, 2, 0, 2, static const uint16_t PERM_12_25[] = {
0, 2, 0, 3, 0, 3, 0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,
1, 3, 1, 3, 1, 3, 1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,
1, 3, 1, 3, 1, 3, 2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,
1, 3, 1, 3, 1, 3, 3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,
1, 3, 1, 3, 1, 3 4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,
5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,
6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,
7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,
8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,
9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,
10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,
11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299
}; };
const int nZ[36] = { 5, 3, 4, 2, 3, 1, static const uint16_t PERM_12_29[] = {
2, 0, 1, 13, 0, 12, 0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,300,312,324,336,
22, 11, 21, 10, 20, 9, 1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,301,313,325,337,
19, 8, 18, 7, 17, 6, 2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,302,314,326,338,
16, 5, 15, 4, 14, 3, 3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,303,315,327,339,
13, 2, 12, 1, 11, 0 4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,304,316,328,340,
5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,305,317,329,341,
6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,306,318,330,342,
7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,307,319,331,343,
8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,308,320,332,344,
9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,309,321,333,345,
10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,310,322,334,346,
11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299,311,323,335,347
}; };
/*
* NXDN SACCH interleave
*/
const unsigned char nsW[72] = {
0, 12, 24, 36, 48, 60,
1, 13, 25, 37, 49, 61,
2, 14, 26, 38, 50, 62,
3, 15, 27, 39, 51, 63,
4, 16, 28, 40, 52, 64,
5, 17, 29, 41, 53, 65,
6, 18, 30, 42, 54, 66,
7, 19, 31, 43, 55, 67,
8, 20, 32, 44, 56, 68,
9, 21, 33, 45, 57, 69,
10,22, 34, 46, 58, 70,
11,23, 35, 47, 59, 71
};
const int DSDNXDN_SACCH_m_Interleave[60] =
{
0, 12, 24, 36, 48,
1, 13, 25, 37, 49,
2, 14, 26, 38, 50,
3, 15, 27, 39, 51,
4, 16, 28, 40, 52,
5, 17, 29, 41, 53,
6, 18, 30, 42, 54,
7, 19, 31, 43, 55,
8, 20, 32, 44, 56,
9, 21, 33, 45, 57,
10, 22, 34, 46, 58,
11, 23, 35, 47, 59,
};
const int DSDNXDN_SACCH_m_PunctureList[12] = { 5, 11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 71 };
const unsigned int DSDNXDN_FACCH1_m_Interleave[144] =
{
0, 16, 32, 48, 64, 80, 96, 112, 128,
1, 17, 33, 49, 65, 81, 97, 113, 129,
2, 18, 34, 50, 66, 82, 98, 114, 130,
3, 19, 35, 51, 67, 83, 99, 115, 131,
4, 20, 36, 52, 68, 84, 100, 116, 132,
5, 21, 37, 53, 69, 85, 101, 117, 133,
6, 22, 38, 54, 70, 86, 102, 118, 134,
7, 23, 39, 55, 71, 87, 103, 119, 135,
8, 24, 40, 56, 72, 88, 104, 120, 136,
9, 25, 41, 57, 73, 89, 105, 121, 137,
10, 26, 42, 58, 74, 90, 106, 122, 138,
11, 27, 43, 59, 75, 91, 107, 123, 139,
12, 28, 44, 60, 76, 92, 108, 124, 140,
13, 29, 45, 61, 77, 93, 109, 125, 141,
14, 30, 46, 62, 78, 94, 110, 126, 142,
15, 31, 47, 63, 79, 95, 111, 127, 143,
};
const unsigned int DSDNXDN_FACCH1_m_PunctureList[48] =
{
1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U,
41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U,
81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U,
121U, 125U, 129U, 133U, 137U, 141U, 145U, 149U, 153U, 157U,
161U, 165U, 169U, 173U, 177U, 181U, 185U, 189U
};
const int DSDNXDN_UDCH_m_Interleave[348] = {
0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, 252, 264, 276, 288, 300, 312, 324, 336,
1, 13, 25, 37, 49, 61, 73, 85, 97, 109, 121, 133, 145, 157, 169, 181, 193, 205, 217, 229, 241, 253, 265, 277, 289, 301, 313, 325, 337,
2, 14, 26, 38, 50, 62, 74, 86, 98, 110, 122, 134, 146, 158, 170, 182, 194, 206, 218, 230, 242, 254, 266, 278, 290, 302, 314, 326, 338,
3, 15, 27, 39, 51, 63, 75, 87, 99, 111, 123, 135, 147, 159, 171, 183, 195, 207, 219, 231, 243, 255, 267, 279, 291, 303, 315, 327, 339,
4, 16, 28, 40, 52, 64, 76, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 208, 220, 232, 244, 256, 268, 280, 292, 304, 316, 328, 340,
5, 17, 29, 41, 53, 65, 77, 89, 101, 113, 125, 137, 149, 161, 173, 185, 197, 209, 221, 233, 245, 257, 269, 281, 293, 305, 317, 329, 341,
6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 126, 138, 150, 162, 174, 186, 198, 210, 222, 234, 246, 258, 270, 282, 294, 306, 318, 330, 342,
7, 19, 31, 43, 55, 67, 79, 91, 103, 115, 127, 139, 151, 163, 175, 187, 199, 211, 223, 235, 247, 259, 271, 283, 295, 307, 319, 331, 343,
8, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140, 152, 164, 176, 188, 200, 212, 224, 236, 248, 260, 272, 284, 296, 308, 320, 332, 344,
9, 21, 33, 45, 57, 69, 81, 93, 105, 117, 129, 141, 153, 165, 177, 189, 201, 213, 225, 237, 249, 261, 273, 285, 297, 309, 321, 333, 345,
10, 22, 34, 46, 58, 70, 82, 94, 106, 118, 130, 142, 154, 166, 178, 190, 202, 214, 226, 238, 250, 262, 274, 286, 298, 310, 322, 334, 346,
11, 23, 35, 47, 59, 71, 83, 95, 107, 119, 131, 143, 155, 167, 179, 191, 203, 215, 227, 239, 251, 263, 275, 287, 299, 311, 323, 335, 347,
};
const int DSDNXDN_UDCH_m_PunctureList[58] = {
3, 11,
17, 25,
31, 39,
45, 53,
59, 67,
73, 81,
87, 95,
101, 109,
115, 123,
129, 137,
143, 151,
157, 165,
171, 179,
185, 193,
199, 207,
213, 221,
227, 235,
241, 249,
255, 263,
269, 277,
283, 291,
297, 305,
311, 319,
325, 333,
339, 347,
353, 361,
367, 375,
381, 389,
395, 403,
};
//#endif /* _MAIN */
#endif

View File

@@ -1,10 +1,8 @@
sudo cp tone8.wav /usr/share/ #!/bin/bash
sudo cp tone24.wav /usr/share/ #
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
mkdir build mkdir build
cd build cd build
cmake .. cmake ..
make -j `nproc` make -j $(nproc)
sudo make install sudo make install
sudo ldconfig sudo ldconfig

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

@@ -0,0 +1,120 @@
diff --git a/src/dmr_block.c b/src/dmr_block.c
index 893b0e8..e7f9de7 100644
--- a/src/dmr_block.c
+++ b/src/dmr_block.c
@@ -783,6 +783,6 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
// sprintf (state->call_string[0], "%s", " "); //21 spaces
// sprintf (state->call_string[1], "%s", " "); //21 spaces
- sprintf (state->dmr_lrrp_gps[0], "%s", "");
- sprintf (state->dmr_lrrp_gps[1], "%s", "");
+ // sprintf (state->dmr_lrrp_gps[0], "%s", ""); //disabled for dmr data call persistence #174
+ // sprintf (state->dmr_lrrp_gps[1], "%s", ""); //disabled for dmr data call persistence #174
}
\ No newline at end of file
diff --git a/src/dmr_data.c b/src/dmr_data.c
index 3541152..3cae906 100644
--- a/src/dmr_data.c
+++ b/src/dmr_data.c
@@ -267,7 +267,20 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
state->color_code_ok = SlotTypeOk;
//not sure why I still have two variables for this, need to look and see what state->color_code still ties into
- if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
+ if (SlotTypeOk == 1)
+ {
+ if (state->dmr_color_code != state->color_code)
+ {
+ //Zero out values on color code change #174
+ state->lasttg = 0;
+ state->lasttgR =0;
+ state->lastsrc = 0;
+ state->lastsrcR = 0;
+ sprintf (state->dmr_lrrp_gps[0], "%s", "");
+ sprintf (state->dmr_lrrp_gps[1], "%s", "");
+ state->dmr_color_code = state->color_code;
+ }
+ }
/* Reconstitute the burst type */
burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
diff --git a/src/dsd_main.c b/src/dsd_main.c
index 5531ef3..5598793 100644
--- a/src/dsd_main.c
+++ b/src/dsd_main.c
@@ -257,10 +257,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
//zero out right away if not trunking
if (opts->p25_trunk == 0)
{
- state->lasttg = 0;
- state->lastsrc = 0;
- state->lasttgR = 0;
- state->lastsrcR = 0;
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
//zero out vc frequencies?
state->p25_vc_freq[0] = 0;
@@ -290,10 +290,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
//mainly bugfix for ncurses and per call wavs (edacs) and also signal fade, etc
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && time(NULL) - state->last_cc_sync_time > opts->trunk_hangtime)
{
- state->lasttg = 0;
- state->lastsrc = 0;
- state->lasttgR = 0;
- state->lastsrcR = 0;
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
}
@@ -431,7 +431,7 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len));
memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
memset(state->dmr_embedded_gps, 0, sizeof(state->dmr_embedded_gps));
- memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
+ // memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
// memset(state->active_channel, 0, sizeof(state->active_channel));
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
index 4646e77..e9ecab1 100644
--- a/src/dsd_ncurses.c
+++ b/src/dsd_ncurses.c
@@ -3104,7 +3104,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
//LRRP
- if(state->dmrburstL != 16) //only during data and no trunking
+ // if(state->dmrburstL != 16) //only during data and no trunking //disabled for dmr data call persistence #174
{
attron(COLOR_PAIR(4));
printw ("%s", state->dmr_lrrp_gps[0]);
@@ -3298,7 +3298,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
//LRRP
- if(state->dmrburstR != 16) //only during data and no trunking
+ // if(state->dmrburstR != 16) //only during data and no trunking //disabled for dmr data call persistence #174
{
attron(COLOR_PAIR(4));
printw ("%s", state->dmr_lrrp_gps[1]);
@@ -3978,10 +3978,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
dmr_reset_blocks (opts, state);
//zero out additional items
- state->lasttg = 0;
- state->lasttgR = 0;
- state->lastsrc = 0;
- state->lastsrcR = 0;
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
state->payload_algid = 0;
state->payload_algidR = 0;
state->payload_keyid = 0;

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

@@ -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,21 +1,15 @@
#! /bin/bash #! /bin/bash
#
clear clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition printf "DSD-FME Digital Speech Decoder - Florida Man Edition
echo Automatic Git Pull and Rebuild Automatic Git Pull and Rebuild\n\n"
echo
sleep 1 sleep 1
##Open your clone folder## ##Open your clone folder##
git pull https://github.com/lwvmobile/dsd-fme pulseaudio git pull
sleep 2 sleep 2
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
##cd into your build folder## ##cd into your build folder##
cd build cd build
##cmake usually isn't necesary, but could be if I update the cmakelist.txt
cmake .. cmake ..
make -j `nproc` make -j $(nproc)
sudo make install sudo make install
sudo ldconfig sudo ldconfig

7
src/1.c Normal file
View File

@@ -0,0 +1,7 @@
/*-------------------------------------------------------------------------------
* 1.c
* Placeholder File 1 -- This file is for temporary code storage
*
*
*
*-----------------------------------------------------------------------------*/

7
src/2.c Normal file
View File

@@ -0,0 +1,7 @@
/*-------------------------------------------------------------------------------
* 2.c
* Placeholder File 2 -- This file is for temporary code storage
*
*
*
*-----------------------------------------------------------------------------*/

594
src/3.c Normal file
View File

@@ -0,0 +1,594 @@
/*-------------------------------------------------------------------------------
* 3.c
* Placeholder File 3 -- This file is for temporary code storage
*
* Multiple 1/2 Rate Convolutional Decoders for NXDN/M17/YSF
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
*-----------------------------------------------------------------------------*/
#include "dsd.h"
static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
// trellis_1_2 encode: source is in bits, result in bits
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
{
for (int i=0; i<result_len; i+=2) {
reg = (reg << 1) | source[i>>1];
result[i] = PARITY[reg & 0x19];
result[i+1] = PARITY[reg & 0x17];
}
}
// simplified trellis 2:1 decode; source and result in bits
// assumes that encoding was done with NTEST trailing zero bits
// result_len should be set to the actual number of data bits
// in the original unencoded message (excl. these trailing bits)
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
{
int reg = 0;
int min_d;
int min_bt;
static const int NTEST = 4;
static const int NTESTC = 1 << NTEST;
uint8_t bt[NTEST];
uint8_t tt[NTEST*2];
int dstats[4];
int sum;
for (int p=0; p < 4; p++)
dstats[p] = 0;
for (int p=0; p < result_len; p++) {
for (int i=0; i<NTESTC; i++) {
bt[0] = (i&8)>>3;
bt[1] = (i&4)>>2;
bt[2] = (i&2)>>1;
bt[3] = (i&1);
trellis_encode(tt, bt, NTEST*2, reg);
sum=0;
for (int j=0; j<NTEST*2; j++) {
sum += tt[j] ^ source[p*2+j];
}
if (i == 0 || sum < min_d) {
min_d = sum;
min_bt = bt[0];
}
}
result[p] = min_bt;
reg = (reg << 1) | min_bt;
dstats[(min_d > 3) ? 3 : min_d] += 1;
}
//debug output
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
}
//Original Copyright/License
/* -*- c++ -*- */
/*
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
*
* This file is part of OP25
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
//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;
}

7
src/4.c Normal file
View File

@@ -0,0 +1,7 @@
/*-------------------------------------------------------------------------------
* 4.c
* Placeholder File 4 -- This file is for temporary code storage
*
*
*
*-----------------------------------------------------------------------------*/

7
src/5.c Normal file
View File

@@ -0,0 +1,7 @@
/*-------------------------------------------------------------------------------
* 5.c
* Placeholder File 5 -- This file is for temporary code storage
*
*
*
*-----------------------------------------------------------------------------*/

View File

@@ -134,6 +134,13 @@ const uint8_t DeInterleaveReverseChannelBptc[32] =
24, 9, 26, 11, 28, 13, 30, 15 24, 9, 26, 11, 28, 13, 30, 15
}; };
const uint8_t DeInterleaveReverseChannelBptcPlacement[32] =
{
0, 16, 1, 17, 2, 18, 3, 19,
4, 20, 5, 21, 6, 22, 7, 23,
8, 24, 9, 25, 10, 26, 11, 27,
12, 28, 13, 29, 14, 30, 15, 31
};
/* Functions ----------------------------------------------------------------*/ /* Functions ----------------------------------------------------------------*/
@@ -192,18 +199,10 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
} }
} }
/* R(0) to R(2) may be used to transport some
* Restricted Access System (RAS) information,
* So save these three bytes before reset all of them
* See patent US 2013/0288643 A1 */
R[0] = DataMatrix[0][2]; /* Save R(0) */
R[1] = DataMatrix[0][1]; /* Save R(1) */
R[2] = DataMatrix[0][0]; /* Save R(2) */
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */ /* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
DataMatrix[0][0] = 0; /* R(2) */ // DataMatrix[0][0] = 0; /* R(2) */
DataMatrix[0][1] = 0; /* R(1) */ // DataMatrix[0][1] = 0; /* R(1) */
DataMatrix[0][2] = 0; /* R(0) */ // DataMatrix[0][2] = 0; /* R(0) */
/* Init the Hamming (15,11,3) library /* Init the Hamming (15,11,3) library
* Not needed because it has already been done * Not needed because it has already been done
@@ -356,6 +355,14 @@ uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DM
} }
} }
/* R(0) to R(2) may be used to transport some
* Restricted Access System (RAS) information,
* So save these three bits after hamming correction
* See patent US 2013/0288643 A1 */
R[0] = DataMatrix[0][2]; /* Save R(0) */
R[1] = DataMatrix[0][1]; /* Save R(1) */
R[2] = DataMatrix[0][0]; /* Save R(2) */
/* Return the number of irrecoverable Hamming errors */ /* Return the number of irrecoverable Hamming errors */
return HammingIrrecoverableErrorNb; return HammingIrrecoverableErrorNb;
} /* End BPTC_196x96_Extract_Data() */ } /* End BPTC_196x96_Extract_Data() */
@@ -498,33 +505,38 @@ uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDat
* DMRDataExtracted[11..15] = Hamming data * DMRDataExtracted[11..15] = Hamming data
* DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked) * DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked)
* *
* @param ParityCheckTypeOdd : 0 = Parity to check is even (used in Non-Reverse Channel Single Burst BPTC)
* 1 = Parity to check is odd (used in Reverse Channel Single Burst BPTC)
*
* @return 0 = All is OK * @return 0 = All is OK
* Other = Error - Irrecoverable Hamming parity check error number * Other = Error - Irrecoverable Hamming parity check error number
*/ */
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32]) uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd)
{ {
uint32_t i; uint32_t i;
uint8_t DataMatrix[32]; uint8_t DataMatrix[32];
uint8_t LineUncorrected[16]; uint8_t LineUncorrected[16];
uint8_t LineCorrected[11]; uint8_t LineCorrected[11];
uint32_t HammingIrrecoverableErrorNb = 0; uint32_t HammingIrrecoverableErrorNb = 0;
uint32_t ParityCheckErrorNb = 0; uint32_t ParityCheckOddErrorNb = 0;
uint32_t ParityCheckEvenErrorNb = 0;
//TODO: make this so we can load either rc interleave, or single burst interleave
for(i = 0; i < 32; i++) for(i = 0; i < 32; i++)
{ {
DataMatrix[DeInterleaveReverseChannelBptc[i]] = InputInterleavedData[i] & 1; DataMatrix[DeInterleaveReverseChannelBptcPlacement[DeInterleaveReverseChannelBptc[i]]] = InputInterleavedData[i] & 1;
} }
/* Copy the entire input buffer to the output buffer */ /* Copy the entire input buffer to the output buffer */
for(i = 0; i < 32; i++) for(i = 0; i < 32; i++)
{ {
DMRDataExtracted[i] = DataMatrix[i]; DMRDataExtracted[i] = DataMatrix[i] & 1;
} }
/* Prepare the line to be corrected */ /* Prepare the line to be corrected */
for(i = 0; i < 16; i++) for(i = 0; i < 16; i++)
{ {
LineUncorrected[i] = DataMatrix[i]; LineUncorrected[i] = DataMatrix[i] & 1;
} }
/* Apply Hamming (16,11,4) code correction */ /* Apply Hamming (16,11,4) code correction */
@@ -536,7 +548,7 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
/* Copy the corrected content to the output buffer */ /* Copy the corrected content to the output buffer */
for(i = 0; i < 11; i++) for(i = 0; i < 11; i++)
{ {
DMRDataExtracted[i] = LineCorrected[i]; DMRDataExtracted[i] = LineCorrected[i] & 1;
} }
/* Check Parity bits */ /* Check Parity bits */
@@ -544,14 +556,24 @@ uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDat
{ {
/* Odd parity ==> If data = 1 then parity = 0 /* Odd parity ==> If data = 1 then parity = 0
* If data = 0 then parity = 1 */ * If data = 0 then parity = 1 */
if(DMRDataExtracted[i] == DMRDataExtracted[i + 16]) ParityCheckErrorNb++; if((DMRDataExtracted[i] & 1) == (DMRDataExtracted[i + 16] & 1)) ParityCheckOddErrorNb++;
if((DMRDataExtracted[i] & 1) != (DMRDataExtracted[i + 16] & 1)) ParityCheckEvenErrorNb++;
} }
//fprintf(stderr, "Hamming ERR=%u ; Parity ERR=%u", HammingIrrecoverableErrorNb, ParityCheckErrorNb); //fprintf(stderr, "Hamming ERR=%u ; Parity odd ERR=%u, Parity even ERR=%u, ", HammingIrrecoverableErrorNb, ParityCheckOddErrorNb, ParityCheckEvenErrorNb);
//fprintf(stderr, "Content =\n");
//for(i = 0; i < 32; i++)
//{
// fprintf(stderr, "%u", DMRDataExtracted[i] & 1);
// if((i == 15) || (i == 31)) fprintf(stderr, "\n");
// else fprintf(stderr, "-");
//}
/* Return the number of irrecoverable Hamming errors + /* Return the number of irrecoverable Hamming errors +
* the number of parity check error */ * the number of parity check error */
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb); if(ParityCheckTypeOdd) return (HammingIrrecoverableErrorNb + ParityCheckOddErrorNb);
else return (HammingIrrecoverableErrorNb + ParityCheckEvenErrorNb);
} /* End BPTC_16x2_Extract_Data() */ } /* End BPTC_16x2_Extract_Data() */

214
src/dmr_34.c Normal file
View File

@@ -0,0 +1,214 @@
/*-------------------------------------------------------------------------------
* dmr_34.c
* DMR (and P25) 3/4 Rate Simple Trellis Decoder
*
* LWVMOBILE
* 2023-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
uint8_t interleave[98] = {
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97,
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91,
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93,
6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95};
//this is a convertion table for converting the dibit pairs into constellation points
uint8_t constellation_map[16] = {
11, 12, 0, 7, 14, 9, 5, 2, 10, 13, 1, 6, 15, 8, 4, 3
};
//digitized dibit to OTA symbol conversion for reference
//0 = +1; 1 = +3;
//2 = -1; 3 = -3;
//finite state machine values
uint8_t fsm[64] = {
0, 8, 4, 12, 2, 10, 6, 14,
4, 12, 2, 10, 6, 14, 0, 8,
1, 9, 5, 13, 3, 11, 7, 15,
5, 13, 3, 11, 7, 15, 1, 9,
3, 11, 7, 15, 1, 9, 5, 13,
7, 15, 1, 9, 5, 13, 3, 11,
2, 10, 6, 14, 0, 8, 4, 12,
6, 14, 0, 8, 4, 12, 2, 10};
//attempt to find the surviving path, or the 'best' path available (most positions gained)
uint8_t fix_34(uint8_t * p, uint8_t state, int position)
{
int i, j, k, counter, best_p, best_v, survivors;
uint8_t temp_s, tri, t;
//status of surviving paths -- debug
int s[8];
memset (s, 0, 8*sizeof(int));
//assign all potentially correct points to temporary storage
uint8_t temp_p[8];
temp_p[0] = (p[position] ^ 1) & 0xF;
temp_p[1] = (p[position] ^ 3) & 0xF;
temp_p[2] = (p[position] ^ 5) & 0xF;
temp_p[3] = (p[position] ^ 7) & 0xF;
temp_p[4] = (p[position] ^ 9) & 0xF;
temp_p[5] = (p[position] ^ 11) & 0xF;
temp_p[6] = (p[position] ^ 13) & 0xF;
temp_p[7] = (p[position] ^ 15) & 0xF;
best_p = 0; //best position
best_v = 0; //best path value
for (k = 0; k < 8; k++)
{
temp_s = state;
counter = 0;
tri = 0;
for (i = position; i < 49; i++)
{
//assign temp t either as our temp_p, or next point of i
if (i == position) t = temp_p[k];
else t = p[i];
if (tri != 0xFF) //while the path survives
{
tri = 0xFF;
for (j = 0; j < 8; j++)
{
if ( fsm[(temp_s*8)+j] == t )
{
//return our tribit value and state for the next point
tri = temp_s = (uint8_t)j;
counter++;
break;
}
}
if (counter > best_p)
{
best_p = counter;
best_v = k; //if we make it further on current path, assign as best path
}
// surviving path -- made it to 49
if (i == 48) s[k] = 1;
}
}
}
//NOTE: If there are no surviving paths, then that means there is another bit/point err
//Ideally, at the end of a single or multiple fixes, there should only be one survivor, but in practice,
//I've seen up to 4 surviving paths and somehow, get a good CRC and a good LRRP or LOCN decode
//multiple survivors seems common when the starting err position is very close to 49
//tally number of surviving paths
survivors = 0;
for (k = 0; k < 8; k++)
{
if (s[k] == 1) survivors++;
}
//debug
// fprintf (stderr, "START: %d; BEST_P: %d; BEST_V: %d; Survivors: %d; Point: %d; ", position, best_p, best_v, survivors, temp_p[best_v]);
return temp_p[best_v]; //return the point value of the best path's starting point value
}
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
{
int i, j;
uint32_t irr_err = 0; //irrecoverable errors
uint8_t deinterleaved_dibits[98];
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
//deinterleave our input dibits
for (i = 0; i < 98; i++)
deinterleaved_dibits[interleave[i]] = input[i];
//pack the input into nibbles (dibit pairs)
uint8_t nibs[49];
memset (nibs, 0, sizeof(nibs));
for (i = 0; i < 49; i++)
nibs[i] = (deinterleaved_dibits[i*2+0] << 2) | (deinterleaved_dibits[i*2+1] << 0);
//convert our dibit pairs into constellation point values
uint8_t point[49];
memset (point, 0xFF, sizeof(point));
for (i = 0; i < 49; i++)
point[i] = constellation_map[nibs[i]];
//debug view points
// fprintf (stderr, "\n P =");
// for (i = 0; i < 49; i++)
// fprintf (stderr, " %02d", point[i]);
//convert constellation points into tribit values using the FSM
uint8_t state = 0;
uint32_t tribits[49];
memset (tribits, 0xF, sizeof(tribits));
for (i = 0; i < 49; i++)
{
for (j = 0; j < 8; j++)
{
if ( fsm[(state*8)+j] == point[i] )
{
//return our tribit value and state for the next point
tribits[i] = state = (uint8_t)j;
break;
}
}
//if tribit value is greater than 7, then we have a decoding error
if (tribits[i] > 7)
{
irr_err++; //tally number of errors
//debug point, position of error, and state value
// fprintf (stderr, "\n P: %d, %d:%d; ", point[i], i, state);
//attempt to fix point by looking for the best path from here
point[i] = fix_34(point, state, i);
//Make a hard decision and flip point to fit in current state
// point[i] ^= 7; //lucky number 7 (0111) //fallback
//decrement one and resume decoding
i--;
}
}
//debug view tribits/states
// fprintf (stderr, "\n T =");
// for (i = 0; i < 49; i++)
// fprintf (stderr, " %02d", tribits[i]);
//convert tribits into a return payload
uint32_t temp = 0;
//break into chunks of 24 bit values and shuffle into 8-bit (byte) treturn values
for (i = 0; i < 6; i++)
{
temp = (tribits[(i*8)+0] << 21) + (tribits[(i*8)+1] << 18) + (tribits[(i*8)+2] << 15) + (tribits[(i*8)+3] << 12) +
(tribits[(i*8)+4] << 9) + (tribits[(i*8)+5] << 6) + (tribits[(i*8)+6] << 3) + (tribits[(i*8)+7] << 0);
treturn[(i*3)+0] = (temp >> 16) & 0xFF;
treturn[(i*3)+1] = (temp >> 8) & 0xFF;
treturn[(i*3)+2] = (temp >> 0) & 0xFF;
}
//trellis point/state err tally
// if (irr_err != 0)
// fprintf (stderr, " P_ERR = %d", irr_err);
return (0);
}

1070
src/dmr_block.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2495
src/dmr_csbk.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -18,35 +18,33 @@
#include "dsd.h" #include "dsd.h"
void void
processDMRdata (dsd_opts * opts, dsd_state * state) dmr_data_sync (dsd_opts * opts, dsd_state * state)
{ {
int i, dibit; int i, dibit;
int *dibit_p; int *dibit_p;
char sync[25]; char sync[25];
char syncdata[48]; char syncdata[48];
char cachdata[25] = {0}; uint8_t cachdata[25];
char cc[5] = {0}; UNUSED(syncdata);
char ccAscii[5] = {0};
char bursttype[5];
unsigned int burst;
char info[196];
uint8_t burst;
char info[196];
unsigned char SlotType[20]; unsigned char SlotType[20];
unsigned int SlotTypeOk; unsigned int SlotTypeOk;
int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; uint8_t cach_err = 0;
UNUSED(cach_err);
#ifdef DMR_DUMP int cachInterleave[24] =
char syncbits[49]; {0, 7, 8, 9, 1, 10,
char cachbits[25]; 11, 12, 2, 13, 14,
int k; 15, 3, 16, 4, 17, 18,
#endif 19, 5, 20, 21, 22, 6, 23
};
ccAscii[4] = 0;
bursttype[4] = 0;
dibit_p = state->dmr_payload_p - 90; dibit_p = state->dmr_payload_p - 90;
// CACH
//collect cach and de-interleave
for (i = 0; i < 12; i++) for (i = 0; i < 12; i++)
{ {
dibit = *dibit_p; dibit = *dibit_p;
@@ -59,73 +57,38 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
dibit = (int)state->dmr_stereo_payload[i]; dibit = (int)state->dmr_stereo_payload[i];
} }
else state->dmr_stereo_payload[i] = dibit;
cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1 cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
} }
//decode and correct cach and compare //seperate tact bits from cach
int cach_okay = 69; uint8_t tact_bits[7];
if ( Hamming_7_4_decode (cachdata) ) //is now de-interleaved appropriately for (i = 0; i < 7; i++)
{ {
cach_okay = 1; tact_bits[i] = cachdata[i];
}
if (cach_okay == 1)
{
//fprintf (stderr, "CACH Okay ");
}
if (cach_okay != 1)
{
//fprintf (stderr, "CACH FEC Error %d", cach_okay);
if (opts->aggressive_framesync == 1) //may not worry about it on data
{
goto END;
}
} }
state->currentslot = cachdata[1]; //run hamming on tact bits
int cach_okay = -1;
if ( Hamming_7_4_decode (tact_bits) ) cach_okay = 1;
else
{
cach_okay = -1;
SlotTypeOk = 0;
goto END;
}
//minor bugfix for MSData when MSData has accumulated data blocks state->currentslot = tact_bits[1];
//(i.e. data header and 1/2 rate data), force all data into slot 0
//in the future, maybe we will remove the hard set on this
if (state->dmr_ms_mode == 1) if (state->dmr_ms_mode == 1)
{ {
state->currentslot = 0; state->currentslot = 0;
} }
if (state->currentslot == 0 && state->dmr_ms_mode == 0)
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot2light[0] = ' ';
state->slot2light[6] = ' ';
}
//else
if (state->currentslot == 1 && state->dmr_ms_mode == 0)
{
state->slot2light[0] = '[';
state->slot2light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
//end correct cach and set slot
#ifdef DMR_DUMP
k = 0;
for (i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
fprintf(stderr, "%s ", cachbits);
#endif
//trellis bits
unsigned char trellisdibits[98];
// Current slot - First half - Data Payload - 1st part // Current slot - First half - Data Payload - 1st part
for (i = 0; i < 49; i++) for (i = 0; i < 49; i++)
{ {
@@ -139,7 +102,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
dibit = (int)state->dmr_stereo_payload[i+12]; dibit = (int)state->dmr_stereo_payload[i+12];
} }
trellisdibits[i] = dibit; else state->dmr_stereo_payload[i+12] = dibit;
info[2*i] = (1 & (dibit >> 1)); // bit 1 info[2*i] = (1 & (dibit >> 1)); // bit 1
info[(2*i)+1] = (1 & dibit); // bit 0 info[(2*i)+1] = (1 & dibit); // bit 0
} }
@@ -153,10 +116,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
} }
if (state->dmr_stereo == 1) if (state->dmr_stereo == 1)
{ {
dibit = (int)state->dmr_stereo_payload[61]; //61, not i+61 dibit = (int)state->dmr_stereo_payload[61];
} }
cc[0] = (1 & (dibit >> 1)); // bit 1 else state->dmr_stereo_payload[61] = dibit;
cc[1] = (1 & dibit); // bit 0
SlotType[0] = (1 & (dibit >> 1)); // bit 1 SlotType[0] = (1 & (dibit >> 1)); // bit 1
SlotType[1] = (1 & dibit); // bit 0 SlotType[1] = (1 & dibit); // bit 0
@@ -170,17 +133,11 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
dibit = (int)state->dmr_stereo_payload[62]; dibit = (int)state->dmr_stereo_payload[62];
} }
cc[2] = (1 & (dibit >> 1)); // bit 1 else state->dmr_stereo_payload[62] = dibit;
cc[3] = (1 & dibit); // bit 0
SlotType[2] = (1 & (dibit >> 1)); // bit 1 SlotType[2] = (1 & (dibit >> 1)); // bit 1
SlotType[3] = (1 & dibit); // bit 0 SlotType[3] = (1 & dibit); // bit 0
ccAscii[0] = cc[0] + '0';
ccAscii[1] = cc[1] + '0';
ccAscii[2] = cc[2] + '0';
ccAscii[3] = cc[3] + '0';
ccAscii[4] = cc[4] + '\0';
dibit = *dibit_p; dibit = *dibit_p;
dibit_p++; dibit_p++;
if (opts->inverted_dmr == 1) if (opts->inverted_dmr == 1)
@@ -189,8 +146,9 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
} }
if (state->dmr_stereo == 1) //state if (state->dmr_stereo == 1) //state
{ {
dibit = (int)state->dmr_stereo_payload[63]; //(int) dibit = (int)state->dmr_stereo_payload[63];
} }
else state->dmr_stereo_payload[63] = dibit;
SlotType[4] = (1 & (dibit >> 1)); // bit 1 SlotType[4] = (1 & (dibit >> 1)); // bit 1
SlotType[5] = (1 & dibit); // bit 0 SlotType[5] = (1 & dibit); // bit 0
@@ -203,8 +161,9 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
} }
if (state->dmr_stereo == 1) //state if (state->dmr_stereo == 1) //state
{ {
dibit = (int)state->dmr_stereo_payload[64]; //(int) dibit = (int)state->dmr_stereo_payload[64];
} }
else state->dmr_stereo_payload[64] = dibit;
SlotType[6] = (1 & (dibit >> 1)); // bit 1 SlotType[6] = (1 & (dibit >> 1)); // bit 1
SlotType[7] = (1 & dibit); // bit 0 SlotType[7] = (1 & dibit); // bit 0
@@ -220,10 +179,11 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
dibit = (int)state->dmr_stereo_payload[65]; dibit = (int)state->dmr_stereo_payload[65];
} }
else state->dmr_stereo_payload[65] = dibit;
SlotType[8] = (1 & (dibit >> 1)); // bit 1 SlotType[8] = (1 & (dibit >> 1)); // bit 1
SlotType[9] = (1 & dibit); // bit 0 SlotType[9] = (1 & dibit); // bit 0
// signalling data or sync // signaling data or sync
for (i = 0; i < 24; i++) for (i = 0; i < 24; i++)
{ {
dibit = *dibit_p; dibit = *dibit_p;
@@ -236,35 +196,24 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
dibit = (int)state->dmr_stereo_payload[i+66]; dibit = (int)state->dmr_stereo_payload[i+66];
} }
else state->dmr_stereo_payload[i+66] = dibit;
syncdata[2*i] = (1 & (dibit >> 1)); // bit 1 syncdata[2*i] = (1 & (dibit >> 1)); // bit 1
syncdata[(2*i)+1] = (1 & dibit); // bit 0 syncdata[(2*i)+1] = (1 & dibit); // bit 0
sync[i] = (dibit | 1) + 48; sync[i] = (dibit | 1) + 48;
} }
sync[24] = 0; sync[24] = 0;
#ifdef DMR_DUMP if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) )
k = 0;
for (i = 0; i < 24; i++)
{
syncbits[k] = syncdata[(k*2)] + 48; // bit 1
k++;
syncbits[k] = syncdata[(k*2)+1] + 48; // bit 0
k++;
}
syncbits[48] = 0;
fprintf(stderr, "%s ", syncbits);
#endif
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) )//|| (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{ {
if (state->currentslot == 0) if (state->currentslot == 0)
{ {
sprintf(state->slot1light, "[slot1]"); sprintf(state->slot1light, "[slot1]");
sprintf(state->slot2light, " slot2 ");
} }
else else
{ {
sprintf(state->slot1light, " slot1 ");
sprintf(state->slot2light, "[slot2]"); sprintf(state->slot2light, "[slot2]");
} }
} }
@@ -273,15 +222,17 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
{ {
state->currentslot = 0; state->currentslot = 0;
sprintf(state->slot1light, "[sLoT1]"); sprintf(state->slot1light, "[sLoT1]");
sprintf(state->slot2light, "[DMODE]");
} }
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
{ {
state->currentslot = 1; state->currentslot = 1;
sprintf(state->slot1light, "[DMODE]");
sprintf(state->slot2light, "[sLoT2]"); sprintf(state->slot2light, "[sLoT2]");
} }
if (opts->errorbars == 1 && state->dmr_ms_mode == 0) if (state->dmr_ms_mode == 0)
{ {
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light); fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
} }
@@ -289,283 +240,106 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
// Slot type - Second part - Parity bit // Slot type - Second part - Parity bit
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
{ {
if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method if (state->dmr_stereo == 0)
{ {
dibit = getDibit(opts, state); dibit = getDibit(opts, state);
} state->dmr_stereo_payload[i+90] = dibit;
if (opts->inverted_dmr == 1)
{
//dibit = (dibit ^ 2);
} }
if (state->dmr_stereo == 1) if (state->dmr_stereo == 1)
{ {
dibit = (int)state->dmr_stereo_payload[i+90]; //double checked these i+ values make sure we are on the right ones dibit = (int)state->dmr_stereo_payload[i+90];
} }
SlotType[(i*2) + 10] = (1 & (dibit >> 1)); // bit 1 SlotType[(i*2) + 10] = (1 & (dibit >> 1)); // bit 1
SlotType[(i*2) + 11] = (1 & dibit); // bit 0 SlotType[(i*2) + 11] = (1 & dibit); // bit 0
} }
/* Check and correct the SlotType (apply Golay(20,8) FEC check) */ /* Check and correct the SlotType (apply Golay(20,8) FEC check) */
// golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors // golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors
if( Golay_20_8_decode(SlotType) ) if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
{
SlotTypeOk = 1;
//fprintf (stderr, "Slot Okay ");
}
else else
{ {
SlotTypeOk = 0;
if (opts->aggressive_framesync == 1) goto END;
{
SlotTypeOk = 0;
goto END;
}
} }
/* Slot Type parity checked => Fill the color code */
state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0); state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0);
state->color_code_ok = SlotTypeOk; state->color_code_ok = SlotTypeOk;
/* Reconstitute the burst type */ //not sure why I still have two variables for this, need to look and see what state->color_code still ties into
//consider assigning this only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
if (state->currentslot == 0)
{
state->dmrburstL = burst;
}
if (state->currentslot == 1)
{
state->dmrburstR = burst;
}
/* Reconstitute the burst type */ /* Reconstitute the burst type */
bursttype[0] = SlotType[4] + '0'; burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
bursttype[1] = SlotType[5] + '0'; if (state->currentslot == 0) state->dmrburstL = burst;
bursttype[2] = SlotType[6] + '0'; if (state->currentslot == 1) state->dmrburstR = burst;
bursttype[3] = SlotType[7] + '0';
bursttype[4] = '\0';
if (strcmp (bursttype, "0000") == 0)
{
sprintf(state->fsubtype, " PI Header ");
}
else if (strcmp (bursttype, "0001") == 0)
{
sprintf(state->fsubtype, " VOICE LC ");
}
else if (strcmp (bursttype, "0010") == 0)
{
sprintf(state->fsubtype, " TLC ");
}
else if (strcmp (bursttype, "0011") == 0)
{
sprintf(state->fsubtype, " CSBK ");
}
else if (strcmp (bursttype, "0100") == 0)
{
sprintf(state->fsubtype, " MBC Header ");
}
else if (strcmp (bursttype, "0101") == 0)
{
sprintf(state->fsubtype, " MBC ");
}
else if (strcmp (bursttype, "0110") == 0)
{
sprintf(state->fsubtype, " DATA Header ");
}
else if (strcmp (bursttype, "0111") == 0)
{
sprintf(state->fsubtype, " RATE 1/2 DATA");
}
else if (strcmp (bursttype, "1000") == 0)
{
sprintf(state->fsubtype, " RATE 3/4 DATA");
}
else if (strcmp (bursttype, "1001") == 0)
{
sprintf(state->fsubtype, " Slot idle ");
}
else if (strcmp (bursttype, "1010") == 0)
{
sprintf(state->fsubtype, " Rate 1 DATA ");
}
else
{
sprintf(state->fsubtype, " ");
}
// Current slot - First half - Data Payload - 1st part // Current slot - Second Half - Data Payload - 2nd part
//trellis
for (i = 0; i < 49; i++) for (i = 0; i < 49; i++)
{ {
if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method if (state->dmr_stereo == 0)
{ {
dibit = getDibit(opts, state); dibit = getDibit(opts, state);
state->dmr_stereo_payload[i+95] = dibit;
} }
if (opts->inverted_dmr == 1)
{
//dibit = (dibit ^ 2);
}
if (state->dmr_stereo == 1) if (state->dmr_stereo == 1)
{ {
dibit = (int)state->dmr_stereo_payload[i+95]; //double checked these i+ values make sure we are on the right ones dibit = (int)state->dmr_stereo_payload[i+95];
} }
trellisdibits[i+49] = dibit;
info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1 info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1
info[(2*i) + 99] = (1 & dibit); // bit 0 info[(2*i) + 99] = (1 & dibit); // bit 0
} }
//
dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
// Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit) //don't run cach on simplex or mono
if (state->dmr_stereo == 0) if (state->dmr_ms_mode == 0 && opts->dmr_mono == 0)
{ {
skipDibit (opts, state, 12 + 49 + 5); cach_err = dmr_cach (opts, state, cachdata);
} }
if (opts->errorbars == 1) //ending line break
{ fprintf(stderr, "\n");
/* Print the color code */
//if (burst == 0b1001 && state->color_code_ok) //only print on idle for data types, otherwise prints on voice frames.
if (SlotTypeOk == 1)
{
fprintf (stderr, "%s", KCYN);
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
fprintf (stderr, "%s", KNRM);
//state->dmr_color_code = state->color_code;
}
else fprintf(stderr, "| ");
//if(state->color_code_ok) fprintf(stderr, "(OK) |");
if(state->color_code_ok) fprintf(stderr, "| (CRC OK ) |"); //add line break
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, "| (CRC ERR) |");
fprintf (stderr, "%s", KNRM);
}
//fprintf (stderr, "\n"); //print line break
if (strcmp (state->fsubtype, " ") == 0)
{
//fprintf(stderr, " Unknown burst type: %s", bursttype);
fprintf(stderr, " Unknown");
}
else
{
fprintf(stderr, "%s", state->fsubtype);
}
}
switch(burst)
{
/* Burst = PI header */
case 0b0000:
{
ProcessDmrPIHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = Voice LC header */
case 0b0001:
{
/* Extract data from Voice LC Header */
ProcessDmrVoiceLcHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = TLC */
case 0b0010:
{
//Not sure if I really care about this in the context of what it shows
ProcessDmrTerminaisonLC(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = CSBK */
case 0b0011:
{
//going to disable until I can find more useful info to present
ProcessCSBK(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = MBC Header */
case 0b0100:
{
ProcessMBChData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = MBC Continuation*/
case 0b0101:
{
ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = DATA Header */
case 0b0110:
{
ProcessDataData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = RATE 1/2 DATA */
case 0b0111:
{
Process12Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = RATE 3/4 DATA */
case 0b1000:
{
//need to keep working on improving the trellis decode, but is partially viable now
Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = Slot idle */
case 0b1001:
{
if(state->color_code_ok && state->dmr_stereo == 0) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok
break;
}
/* Burst = Rate 1 DATA */
case 0b1010:
{
Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = Unified Single Block DATA */
case 0b1101:
{
ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Default */
default:
{
/* Nothing to do */
ProcessReservedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
} /* End switch(burst) */
if (opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
END: END:
if (SlotTypeOk == 0 || cach_okay != 1) if (SlotTypeOk == 0 || cach_okay != 1)
{ {
fprintf (stderr, "%s", KRED); fprintf (stderr, "%s", KRED);
fprintf (stderr, "| ** CACH or Burst Type FEC ERR ** "); fprintf (stderr, "| CACH/Burst FEC ERR");
fprintf (stderr, "%s", KNRM); fprintf (stderr, "%s", KNRM);
fprintf (stderr, "\n"); fprintf (stderr, "\n");
dmr_reset_blocks (opts, state); //failsafe to reset all data header and blocks when bad tact or slottype
} }
} /* End processDMRdata() */ // Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit)
if (state->dmr_stereo == 0)
{
skipDibit (opts, state, 12 + 49 + 5);
}
#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)
{
int clear = 0;
//IF both slots currently signalling IDLE
if (state->dmrburstL == 9 && state->dmrburstR == 9) clear = 1;
if (clear == 1)
{
state->last_cc_sync_time = 0;
state->last_vc_sync_time = 0;
}
}
#endif
}

647
src/dmr_dburst.c Normal file
View File

@@ -0,0 +1,647 @@
/*-------------------------------------------------------------------------------
* dmr_dburst.c
* DMR Data Burst Handling and related BPTC/FEC/CRC Functions
*
* Portions of BPTC/FEC/CRC code from LouisErigHerve
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
*
* LWVMOBILE
* 2023-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
//TODO: Test USBD LIP Decoder with Real World Samples (if/when available)
//TODO: Test UDT NMEA and LIP Decoders with Real World Samples (if/when available)
//WIP: Move all extra decoders for location, etc, to a new file and add prototypes to dsd.h
//TODO: Test CRC9/CRC32 on Rate 1 Data with Real World Samples (if/when available)
//TODO: Address areas that require reading of ISO7, ISO8, and UTF-16 string formats
#include "dsd.h"
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst)
{
uint32_t i, j, k;
uint32_t CRCExtracted = 0;
uint32_t CRCComputed = 0;
uint32_t CRCCorrect = 0;
uint32_t IrrecoverableErrors = 0;
uint8_t slot = state->currentslot;
//confirmed data
uint8_t dbsn = 0; //data block serial number for confirmed data blocks
uint8_t blockcounter = 0; //local block count
uint8_t confdatabits[250]; //array to reshuffle conf data block bits into sequence for crc9 check
memset (confdatabits, 0, sizeof(confdatabits));
UNUSED(dbsn);
//BPTC 196x96 Specific
uint8_t BPTCDeInteleavedData[196];
uint8_t BPTCDmrDataBit[96];
uint8_t BPTCDmrDataByte[12];
//Embedded Signalling Specific
uint8_t BptcDataMatrix[8][16];
uint8_t LC_DataBit[77];
uint8_t LC_DataBytes[10];
int Burst = -1;
memset (BPTCDeInteleavedData, 0, sizeof(BPTCDeInteleavedData));
memset (BPTCDmrDataBit, 0, sizeof(BPTCDmrDataBit));
memset (BPTCDmrDataByte, 0, sizeof(BPTCDmrDataByte));
memset (BptcDataMatrix, 0, sizeof(BptcDataMatrix));
memset (LC_DataBit, 0, sizeof(LC_DataBit));
memset (LC_DataBytes, 0, sizeof(LC_DataBytes));
//PDU Bytes and Bits
uint8_t DMR_PDU[25];
uint8_t DMR_PDU_bits[196];
memset (DMR_PDU, 0, sizeof (DMR_PDU));
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
uint8_t R[3];
uint8_t BPTCReservedBits = 0;
uint8_t is_ras = 0;
uint8_t crc_original_validity = 0;
uint32_t crcmask = 0;
uint8_t crclen = 0;
uint8_t is_bptc = 0;
uint8_t is_trellis = 0;
uint8_t is_emb = 0;
uint8_t is_lc = 0;
uint8_t is_full = 0;
uint8_t is_udt = 0;
uint8_t pdu_len = 0;
uint8_t pdu_start = 0; //starting value of pdu (0 normal, 2 for confirmed)
uint8_t usbd_st = 0; //usbd service type
switch(databurst){
case 0x00: //PI
is_bptc = 1;
crclen = 16;
crcmask = 0x6969; //insert pi and 69 jokes here
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " PI ");
break;
case 0x01: //VLC
is_bptc = 1;
is_lc = 1;
crclen = 24;
crcmask = 0x969696;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " VLC ");
break;
case 0x02: //TLC
is_bptc = 1;
is_lc = 1;
crcmask = 0x999999;
crclen = 24;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " TLC ");
break;
case 0x03: //CSBK
is_bptc = 1;
crclen = 16;
crcmask = 0xA5A5;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " CSBK");
break;
case 0x04: //MBC Header
is_bptc = 1;
crclen = 16;
crcmask = 0xAAAA;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " MBCH");
break;
case 0x05: //MBC Continuation
is_bptc = 1;
//let block assembler carry out crc on the completed message
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " MBCC");
break;
case 0x06: //Data Header
is_bptc = 1;
crclen = 16;
crcmask = 0xCCCC;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " DATA");
break;
case 0x07: //1/2 Rate Data
is_bptc = 1;
crclen = 9; //confirmed data only
crcmask = 0x0F0;
pdu_len = 12; //12 bytes unconfirmed
sprintf(state->fsubtype, " R12U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 10;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R12C ");
}
if (state->data_header_format[slot] == 0) //UDT 1/2 Encoded Blocks
{
is_udt = 1;
sprintf(state->fsubtype, " UDTC ");
}
break;
case 0x08: //3/4 Rate Data
is_trellis = 1;
crclen = 9; //confirmed data only
crcmask = 0x1FF;
pdu_len = 18; //18 bytes unconfirmed
sprintf(state->fsubtype, " R34U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 16;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R34C ");
}
break;
case 0x09: //Idle
//pseudo-random data fill, no need to do anything with this
sprintf(state->fsubtype, " IDLE ");
break;
case 0x0A: //1 Rate Data
crclen = 9; //confirmed data only
crcmask = 0x10F;
is_full = 1;
pdu_len = 25; //196 bits - 24.5 bytes
sprintf(state->fsubtype, " R_1U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 23;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R_1C ");
}
break;
case 0x0B: //Unified Single Block Data USBD
is_bptc = 1;
crclen = 16;
crcmask = 0x3333;
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " USBD ");
break;
//special types (not real data 'sync' bursts)
case 0xEB: //Embedded Signalling
crclen = 5;
is_emb = 1;
pdu_len = 9;
break;
default:
//Slot Type FEC should catch this so we never see it,
//but if it doesn't, then we can still dump the entire 'packet'
//treat like rate 1 unconfirmed data
is_full = 1;
pdu_len = 25; //196 bits - 24.5 bytes
sprintf(state->fsubtype, " _UNK ");
break;
}
//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 (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
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 98 ", slot+1); //'98' is CACH designation value
for (i = 0; i < 6; i++) //3 byte CACH
{
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", cach_byte); //nibble, not a byte, next time I look at this and wonder why its not %02X
}
fprintf (pFile, "\n%d %02X ", slot+1, databurst); //use hex value of current data burst type
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
}
//Most Data Sync Burst types will use the bptc 196x96
if (is_bptc)
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0;
/* Deinterleave DMR data */
BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData);
/* Extract the BPTC 196,96 DMR data */
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, R);
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x04);
//debug print
//fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]);
/* Convert the 96 bits BPTC data into 12 bytes */
k = 0;
for(i = 0; i < 12; i++)
{
BPTCDmrDataByte[i] = 0;
for(j = 0; j < 8; j++)
{
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] << 1;
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] | (BPTCDmrDataBit[k] & 0x01);
k++;
}
}
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
CRCExtracted = 0;
for(i = 0; i < crclen; i++)
{
CRCExtracted = CRCExtracted << 1;
CRCExtracted = CRCExtracted | (uint32_t)(BPTCDmrDataBit[i + 96 - crclen] & 1);
}
/* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */
CRCExtracted = CRCExtracted ^ crcmask;
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
{
CRCComputed = 0;
CRCExtracted = 0;
CRCCorrect = 1;
}
//run CRC9 on intermediate and last 1/2 confirmed data blocks
else if (state->data_conf_data[slot] == 1 && databurst == 0x7)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the BPTCDmrDataBit array into confdatabits, just for CRC9 check
//need to find a sample to confirm this
for(i = 0; i < 80; i++) confdatabits[i] = BPTCDmrDataBit[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 80] = BPTCDmrDataBit[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 87);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else state->data_block_crc_valid[slot][blockcounter] = 0;
}
//run CCITT on other data forms
else
{
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
else CRCCorrect = 0;
}
//set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs)
if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1;
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
if (BPTCDmrDataByte[1] == 0x68) is_ras = 0;
//if this is a RAS system, set the CRC to okay if irrecoverable errors are okay
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
if (is_ras == 1)
{
crc_original_validity = CRCCorrect;
CRCCorrect = 1;
}
if (databurst == 0x04 || databurst == 0x06) //MBC Header, Data Header
{
if (CRCCorrect)
{
state->data_block_crc_valid[slot][0] = 1;
}
else state->data_block_crc_valid[slot][0] = 0;
}
/* Convert corrected x bytes into x*8 bits */
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
{
BPTCDmrDataBit[j + 0] = (BPTCDmrDataByte[i+pdu_start] >> 7) & 0x01;
BPTCDmrDataBit[j + 1] = (BPTCDmrDataByte[i+pdu_start] >> 6) & 0x01;
BPTCDmrDataBit[j + 2] = (BPTCDmrDataByte[i+pdu_start] >> 5) & 0x01;
BPTCDmrDataBit[j + 3] = (BPTCDmrDataByte[i+pdu_start] >> 4) & 0x01;
BPTCDmrDataBit[j + 4] = (BPTCDmrDataByte[i+pdu_start] >> 3) & 0x01;
BPTCDmrDataBit[j + 5] = (BPTCDmrDataByte[i+pdu_start] >> 2) & 0x01;
BPTCDmrDataBit[j + 6] = (BPTCDmrDataByte[i+pdu_start] >> 1) & 0x01;
BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01;
}
//convert to DMR_PDU and DMR_PDU_bits
for (i = 0; i < pdu_len; i++)
{
DMR_PDU[i] = BPTCDmrDataByte[i+pdu_start];
}
for (i = 0; i < pdu_len * 8; i++)
{
DMR_PDU_bits[i] = BPTCDmrDataBit[i];
}
}
//Embedded Signalling will use BPTC 128x77
if (is_emb)
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0;
/* First step : Reconstitute the BPTC 16x8 matrix */
Burst = 1; /* Burst B to E contains embedded signaling data */
k = 0;
for(i = 0; i < 16; i++)
{
for(j = 0; j < 8; j++)
{
/* Only the LSBit of the byte is stored */
BptcDataMatrix[j][i] = state->dmr_embedded_signalling[slot][Burst][k+8];
k++;
/* Go on to the next burst once 32 bit
* of the SNYC have been stored */
if(k >= 32)
{
k = 0;
Burst++;
}
} /* End for(j = 0; j < 8; j++) */
} /* End for(i = 0; i < 16; i++) */
/* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */
IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
/* Reconstitute the 5 bit CRC */
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
/* Compute the 5 bit CRC */
CRCComputed = ComputeCrc5Bit(LC_DataBit);
if(CRCExtracted == CRCComputed) CRCCorrect = 1;
else CRCCorrect = 0;
for (i = 0; i < 72; i++)
{
DMR_PDU_bits[i] = LC_DataBit[i];
}
for (i = 0; i < 9; i++)
{
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&LC_DataBit[i*8], 8);
}
}
//the sexy one
if (is_trellis)
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 1;
uint8_t tdibits[98];
memset (tdibits, 0, sizeof(tdibits));
//reconstitute info bits into dibits for the trellis decoder
for (i = 0; i < 98; i++)
tdibits[i] = (info[i*2] << 1) | info[i*2+1];
uint8_t TrellisReturn[18];
memset (TrellisReturn, 0, sizeof(TrellisReturn));
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
//NOTE: IrrecoverableErrors in this context are a tally of errors from trellis
//they may have been successfully corrected, the CRC will reveal as much
for (i = 0; i < pdu_len; i++)
DMR_PDU[i] = TrellisReturn[i+pdu_start];
for(i = 0, j = 0; i < 18; i++, j+=8)
{
DMR_PDU_bits[j + 0] = (TrellisReturn[i] >> 7) & 0x01;
DMR_PDU_bits[j + 1] = (TrellisReturn[i] >> 6) & 0x01;
DMR_PDU_bits[j + 2] = (TrellisReturn[i] >> 5) & 0x01;
DMR_PDU_bits[j + 3] = (TrellisReturn[i] >> 4) & 0x01;
DMR_PDU_bits[j + 4] = (TrellisReturn[i] >> 3) & 0x01;
DMR_PDU_bits[j + 5] = (TrellisReturn[i] >> 2) & 0x01;
DMR_PDU_bits[j + 6] = (TrellisReturn[i] >> 1) & 0x01;
DMR_PDU_bits[j + 7] = (TrellisReturn[i] >> 0) & 0x01;
}
//set CRC to correct on unconfirmed 3/4 data blocks (for reporting due to no CRC available on these)
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
//run CRC9 on intermediate and last 3/4 data blocks
else if (state->data_conf_data[slot] == 1)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 135);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else
state->data_block_crc_valid[slot][blockcounter] = 0;
}
//reorganize the DMR_PDU_bits into PDU friendly format (minus the dbsn and crc9)
memset (DMR_PDU_bits, 0, sizeof(DMR_PDU_bits));
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
{
DMR_PDU_bits[j + 0] = (TrellisReturn[i+pdu_start] >> 7) & 0x01;
DMR_PDU_bits[j + 1] = (TrellisReturn[i+pdu_start] >> 6) & 0x01;
DMR_PDU_bits[j + 2] = (TrellisReturn[i+pdu_start] >> 5) & 0x01;
DMR_PDU_bits[j + 3] = (TrellisReturn[i+pdu_start] >> 4) & 0x01;
DMR_PDU_bits[j + 4] = (TrellisReturn[i+pdu_start] >> 3) & 0x01;
DMR_PDU_bits[j + 5] = (TrellisReturn[i+pdu_start] >> 2) & 0x01;
DMR_PDU_bits[j + 6] = (TrellisReturn[i+pdu_start] >> 1) & 0x01;
DMR_PDU_bits[j + 7] = (TrellisReturn[i+pdu_start] >> 0) & 0x01;
}
}
if (is_full) //Rate 1 Data
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0; //implicit, since there is no encoding
for (i = 0; i < 12; i++)
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8);
//Skip Padding Bits (96,97,98,99)
for (i = 0; i < 12; i++)
DMR_PDU[i+12] = (uint8_t)ConvertBitIntoBytes(&info[(i*8)+100], 8);
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
//run CRC9 on intermediate and last 1 rate data blocks
else if (state->data_conf_data[slot] == 1)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&info[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&info[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the info bit array into confdatabits, just for CRC9 check
//unconfirmed, haven't seen any samples with rate 1 data
for(i = 0; i < 176; i++) confdatabits[i] = info[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 176] = info[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 183);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else state->data_block_crc_valid[slot][blockcounter] = 0;
}
//copy info to dmr_pdu_bits
memcpy(DMR_PDU_bits, info, sizeof(DMR_PDU_bits));
}
//time for some pi
if (databurst == 0x00) dmr_pi (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
//full link control
if (databurst == 0x01) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 1); //VLC
if (databurst == 0x02) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 2); //TLC
if (databurst == 0xEB) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 3); //EMB
//dmr data header and multi block types (header, 1/2, 3/4, 1, UDT) - type 1
if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors);
if (databurst == 0x08) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //3/4 Rate Data
if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data
if (databurst == 0x07 && is_udt == 0) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //1/2 Rate Data
if (databurst == 0x07 && is_udt == 1) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 3); //UDT with 1/2 Rate Encoding
//control signalling types (CSBK, MBC)
if (databurst == 0x03) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors);
//both MBC header and MBC continuation will go to the block_assembler - type 2, and then to dmr_cspdu
if (databurst == 0x04)
{
state->data_block_counter[slot] = 0; //zero block counter before running header
state->data_header_valid[slot] = 1; //set valid header since we received one
dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
}
if (databurst == 0x05) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
//Unified Single Data Block (USBD) -- Not to be confused with Unified Data Transport (UDT)
if (databurst == 0x0B)
{
//TODO: provide more robust handling at a later date -- ETSI TS 102 361-4 V1.11.1 (2021-01) 6.6.11.3
usbd_st = (uint8_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 4);
fprintf (stderr, "%s\n", KYEL);
fprintf (stderr, " USBD - ");
if (usbd_st == 0) lip_protocol_decoder (opts, state, DMR_PDU_bits);
else if (usbd_st > 8) fprintf (stderr, "Manufacturer Specific Service %d ", usbd_st);
else fprintf (stderr, "Reserved %d ", usbd_st);
}
//set the original CRCCorrect back to its original value if the RAS flag was tripped
if (is_ras == 1) CRCCorrect = crc_original_validity;
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
// if (IrrecoverableErrors == 0 && CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) fprintf(stderr, "(CRC OK)");
// if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
// {
// fprintf (stderr, "%s", KYEL);
// fprintf(stderr, " (FEC OK)");
// fprintf (stderr, "%s", KNRM);
// }
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " (FEC ERR)");
fprintf (stderr, "%s", KNRM);
}
//print whether or not the 'RAS Field' bits are set to indicate RAS enabled (to be verified)
if (is_ras == 1)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " -RAS ");
//the value of this field seems to always, or usually, be 4, or just R[2] bit is set
if (opts->payload == 1) fprintf (stderr, "%X ", BPTCReservedBits);
fprintf (stderr, "%s", KNRM);
}
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && is_ras == 0 && databurst != 0x09 && databurst != 0x05)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR) ");
fprintf (stderr, "%s", KNRM);
}
//print the unified PDU format here, if not slot idle
if (opts->payload == 1 && databurst != 0x09)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " DMR PDU Payload ");
for (i = 0; i < pdu_len; i++)
{
fprintf (stderr, "[%02X]", DMR_PDU[i]);
}
//debug print
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
fprintf (stderr, "%s", KNRM);
}
}

1245
src/dmr_flco.c Normal file

File diff suppressed because it is too large Load Diff

494
src/dmr_le.c Normal file
View File

@@ -0,0 +1,494 @@
/*-------------------------------------------------------------------------------
* dmr_le.c
* DMR Late Entry MI Fragment Assembly, Procesing, and related Alg functions
*
* LWVMOBILE
* 2022-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
//gather ambe_fr mi fragments for processing
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, uint8_t ambe_fr[4][24], uint8_t ambe_fr2[4][24], uint8_t ambe_fr3[4][24])
{
uint8_t slot = state->currentslot;
//enforce RC4 due to missing PI header, but with valid SVC Opts
//ideally, this would be handled by VC-F single burst, but its not fully reliable compared to this
//due to multiple signalling occurring inside of it, depending on system type
if (state->M == 0x21)
{
if (slot == 0 && state->dmr_so & 0x40)
{
state->payload_algid = 0x21;
state->payload_keyid = 0xFF;
}
if (slot == 1 && state->dmr_soR & 0x40)
{
state->payload_algidR = 0x21;
state->payload_keyidR = 0xFF;
}
}
//collect our fragments and place them into storage
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
state->late_entry_mi_fragment[slot][vc][2] = (uint64_t)ConvertBitIntoBytes(&ambe_fr3[3][0], 4);
if (vc == 6) dmr_late_entry_mi (opts, state);
}
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
{
UNUSED(opts);
uint8_t slot = state->currentslot;
int i, j;
int g[3];
unsigned char mi_go_bits[24];
uint64_t mi_test = 0;
uint64_t go_test = 0;
uint64_t mi_corrected = 0;
uint64_t go_corrected = 0;
uint8_t mi_bits[36];
memset (mi_bits, 0, sizeof(mi_bits));
uint8_t mi_crc_cmp = 0;
uint8_t mi_crc_ext = 1;
uint8_t mi_crc_ok = 0;
mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) |
(state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) |
(state->late_entry_mi_fragment[slot][1][2] << 8) | (state->late_entry_mi_fragment[slot][2][2] << 4) | (state->late_entry_mi_fragment[slot][3][2] << 0);
go_test = (state->late_entry_mi_fragment[slot][4][0] << 32L) | (state->late_entry_mi_fragment[slot][5][0] << 28) | (state->late_entry_mi_fragment[slot][6][0] << 24) |
(state->late_entry_mi_fragment[slot][4][1] << 20) | (state->late_entry_mi_fragment[slot][5][1] << 16) | (state->late_entry_mi_fragment[slot][6][1] << 12) |
(state->late_entry_mi_fragment[slot][4][2] << 8) | (state->late_entry_mi_fragment[slot][5][2] << 4) | (state->late_entry_mi_fragment[slot][6][2] << 0);
for (j = 0; j < 3; j++)
{
for (i = 0; i < 12; i++)
{
mi_go_bits[i] = (( mi_test << (i+j*12) ) & 0x800000000) >> 35;
mi_go_bits[i+12] = (( go_test << (i+j*12) ) & 0x800000000) >> 35;
}
//execute golay decode and assign pass or fail to g
if ( Golay_24_12_decode(mi_go_bits) ) g[j] = 1;
else g[j] = 0;
for (i = 0; i < 12; i++)
{
mi_corrected = mi_corrected << 1;
mi_corrected |= mi_go_bits[i];
go_corrected = go_corrected << 1;
go_corrected |= mi_go_bits[i+12];
//manipulate for crc check
mi_bits[i+(j*12)] = mi_go_bits[i];
}
}
int mi_final = 0;
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
mi_crc_ext = (uint8_t)ConvertBitIntoBytes(&mi_bits[32], 4);
mi_crc_cmp = crc4(mi_bits, 32);
if (mi_crc_ext == mi_crc_cmp)
mi_crc_ok = 1;
//debug -- working now
// fprintf (stderr, " LE MI: %09llX; CRC EXT: %X; CRC CMP: %X; \n", mi_corrected, mi_crc_ext, mi_crc_cmp);
if (g[0] && g[1] && g[2])
{
if (slot == 0 && state->payload_algid != 0)
{
if (state->payload_mi != mi_final)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_mi, mi_final);
if (mi_crc_ok == 1) state->payload_mi = mi_final;
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
else fprintf (stderr, "(CRC ERR)");
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
//run afterwards, or le verification won't match up properly
if (state->payload_algid != 0x21)
{
LFSR64 (state);
fprintf (stderr, "\n");
}
}
if (slot == 1 && state->payload_algidR != 0)
{
if (state->payload_miR != mi_final)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_miR, mi_final);
if (mi_crc_ok == 1) state->payload_miR = mi_final;
if (mi_crc_ok == 1) fprintf (stderr, "(CRC OK)");
else fprintf (stderr, "(CRC ERR)");
fprintf (stderr, "\n");
fprintf (stderr, "%s", KNRM);
}
//run afterwards, or le verification won't match up properly
if (state->payload_algidR != 0x21)
{
LFSR64 (state);
fprintf (stderr, "\n");
}
}
}
}
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
{
UNUSED(opts);
if (state->currentslot == 0)
{
state->dropL = 256;
if (state->K1 != 0)
{
state->DMRvcL = 0;
}
if (state->payload_algid == 0x21)
{
LFSR (state);
fprintf (stderr, "\n");
}
//LFSR64 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
}
if (state->currentslot == 1)
{
state->dropR = 256;
if (state->K1 != 0)
{
state->DMRvcR = 0;
}
if (state->payload_algidR == 0x21)
{
LFSR (state);
fprintf (stderr, "\n");
}
//LFSR64 carried out after LE verification in order to keep it from constantly resetting the MI to the previous value
}
}
void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
{
UNUSED(opts);
state->dropL = 256;
state->dropR = 256;
state->DMRvcL = 0;
state->DMRvcR = 0;
state->payload_miP = 0;
state->payload_miN = 0;
}
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
{
int i;
uint8_t slot = state->currentslot;
uint8_t sbrc_interleaved[32];
uint8_t sbrc_return[32];
uint8_t sbrc_retcrc[32]; //crc significant bits of the return for SB
memset (sbrc_interleaved, 0, sizeof(sbrc_interleaved));
memset (sbrc_return, 0, sizeof(sbrc_return));
memset (sbrc_retcrc, 0, sizeof(sbrc_retcrc));
uint32_t irr_err = 0;
uint32_t sbrc_hex = 0;
uint16_t crc_extracted = 7777;
uint16_t crc_computed = 9999;
uint8_t crc7_okay = 0; //RC
uint8_t crc3_okay = 0; //TXI
uint8_t txi = 0; //SEE: https://patents.google.com/patent/US8271009B2
UNUSED(txi);
//NOTE: Any previous mentions to Cap+ in this area may have been in error,
//The signalling observed here was actually TXI information, not Cap+ Specifically
//check to see if this a TXI system
if (slot == 0 && state->dmr_so & 0x20) txi = 1;
if (slot == 1 && state->dmr_soR & 0x20) txi = 1;
// 9.3.2 Pre-emption and power control Indicator (PI)
// 0 - The embedded signalling carries information associated to the same logical channel or the Null embedded message
// 1 - The embedded signalling carries RC information associated to the other logical channel
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
//power == 0 should be single burst
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
if (power == 1) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 1);
//bad emb burst, never set a valid power indicator value (probably 9)
if (power > 1) goto SBRC_END;
//arrange the return for proper order for the crc3 check
for (i = 0; i < 8; i++) sbrc_retcrc[i] = sbrc_return[i+3];
//RC Channel CRC 7 Mask = 0x7A; CRC bits are used as privacy indicators on
//Single Voice Burst F (see below), other moto values seem to exist there as well -- See TXI patent
if (power == 1) //RC
{
crc_extracted = 0;
for (i = 0; i < 7; i++)
{
crc_extracted = crc_extracted << 1;
crc_extracted = crc_extracted | sbrc_return[i+4];
}
crc_extracted = crc_extracted ^ 0x7A;
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
{
crc_extracted = 0;
for (i = 0; i < 3; i++)
{
crc_extracted = crc_extracted << 1;
crc_extracted = crc_extracted | sbrc_return[i]; //first 3 most significant bits
}
crc_computed = crc3((uint8_t *) sbrc_retcrc, 8); //working now seems consistent as well
if (crc_extracted == crc_computed) crc3_okay = 1;
// fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
}
// else //crc_okay = 0; //CRC invalid / not available when is ENC Identifiers (I really hate that)
for(i = 0; i < 11; i++)
{
sbrc_hex = sbrc_hex << 1;
sbrc_hex |= sbrc_return[i] & 1;
}
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people
{
fprintf (stderr, "%s", KCYN);
if (power == 0) fprintf (stderr, " SB: ");
if (power == 1) fprintf (stderr, " RC: ");
for(i = 0; i < 11; i++)
fprintf (stderr, "%d", sbrc_return[i]);
fprintf (stderr, " - %03X; ", sbrc_hex);
fprintf (stderr, "%s", KNRM);
// if (crc_okay == 0) //forego this since the crc can vary or not be used at all
// {
// fprintf (stderr, "%s", KRED);
// fprintf (stderr, " (CRC ERR)");
// fprintf (stderr, "%s", KNRM);
// fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
// }
fprintf (stderr, "\n");
}
uint8_t sbrc_opcode = sbrc_hex & 0x7; //opcode and alg the same bits, but the alg is present when CRC is bad (I know they are limited on bits, but I hate that idea)
uint8_t alg = sbrc_hex & 0x7; //SEE: https://patents.google.com/patent/EP2347540B1/en
uint8_t key = (sbrc_hex >> 3) & 0xFF;
uint8_t txi_delay = (sbrc_hex >> 3) & 0x1F; //middle five are the 'delay' value on a TXI system
//Note: AES-256 Key 1 will pass a CRC3 due to its bit arrangement vs the CRC poly 1101
// if (irr_err == 0 && sbrc_hex = 0xD) crc3_okay = 0; //SB: 00000001101
//NOTE: on above, I belive that we need to check by opcode as well, as a CRC3 can have multiple collisions
//so we need to exclude op/alg 0 and 3 from the check (does algID 0x03/0x23 even exist?)
if (opts->dmr_le == 1)
{
if (irr_err != 0)
{
uint32_t sbrcpl = 0;
for(i = 0; i < 32; i++)
{
sbrcpl = sbrcpl << 1;
sbrcpl |= sbrc_interleaved[i] & 1;
}
if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, "%s SLOT %d SB/RC (FEC ERR) E:%d; I:%08X D:%03X; %s ", KRED, slot+1, irr_err, sbrcpl, sbrc_hex, KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
}
if (irr_err == 0)
{
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)
// {
// placeholder for future conditions
// }
else if (crc7_okay == 1)
{
//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
else if (crc3_okay == 1 && (sbrc_opcode == 0 || sbrc_opcode == 3) )
{
//opcodes -- 0 (NULL), BR Delay (3)
if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " TXI Op: %X -", sbrc_opcode);
if (sbrc_opcode == 0) fprintf (stderr, " Null; ");
else if (sbrc_opcode == 3)
{
if (txi_delay != 0)
fprintf (stderr, " BR Delay: %d - %d ms;", txi_delay, txi_delay * 30); //could also indicate number of superframes until next VC6 pre-emption
else fprintf (stderr, "BR Delay: Irrelevant / Send at any time;");
//alignment of inbound backwards channel and outbound burst
if (txi_delay == 2) fprintf (stderr, " SF3, Burst E;"); //E is inbound
if (txi_delay == 4) fprintf (stderr, " SF3, Burst D;"); //D is inbound
if (txi_delay == 6) fprintf (stderr, " SF3, Burst C;"); //C is inbound
if (txi_delay == 8) fprintf (stderr, " SF3, Burst B;"); //B is inbound
}
else fprintf (stderr, " Unk; ");
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n"); //only during payload
}
else if (sbrc_opcode != 0 && sbrc_opcode != 3) //all that should be left in this field is the potential ENC identifiers
{
if (slot == 0) //may not need the state->errs anymore //&& state->errs < 3
{
if (state->dmr_so & 0x40 && key != 0 && alg != 0)
{
//if we aren't forcing a particular alg or privacy key set
if (state->M == 0)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
if (state->payload_keyid != key)
state->payload_keyid = key;
if (state->payload_algid != alg)
state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
}
}
}
if (slot == 1) //may not need the state->errs anymore //&& state->errsR < 3
{
if (state->dmr_soR & 0x40 && key != 0 && alg != 0)
{
//if we aren't forcing a particular alg or privacy key set
if (state->M == 0)
{
fprintf (stderr, "\n");
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR LE SB ALG ID: 0x%02X KEY ID: 0x%02X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
if (state->payload_keyidR != key)
state->payload_keyidR = key;
if (state->payload_algidR != alg)
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
}
}
}
}
}
}
SBRC_END:
//'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 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)
{
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);
}
}
uint8_t crc3(uint8_t bits[], unsigned int len)
{
uint8_t crc=0;
unsigned int K = 3;
//x^3+x+1
uint8_t poly[4] = {1,1,0,1};
uint8_t buf[256];
if (len+K > sizeof(buf)) {
return 0;
}
memset (buf, 0, sizeof(buf));
for (unsigned int i=0; i<len; i++){
buf[i] = bits[i];
}
for (unsigned int i=0; i<len; i++)
if (buf[i])
for (unsigned int j=0; j<K+1; j++)
buf[i+j] ^= poly[j];
for (unsigned int i=0; i<K; i++){
crc = (crc << 1) + buf[len + i];
}
return crc;
}
uint8_t crc4(uint8_t bits[], unsigned int len)
{
uint8_t crc=0;
unsigned int K = 4;
//x^4+x+1
uint8_t poly[5] = {1,0,0,1,1};
uint8_t buf[256];
if (len+K > sizeof(buf)) {
return 0;
}
memset (buf, 0, sizeof(buf));
for (unsigned int i=0; i<len; i++){
buf[i] = bits[i];
}
for (unsigned int i=0; i<len; i++)
if (buf[i])
for (unsigned int j=0; j<K+1; j++)
buf[i+j] ^= poly[j];
for (unsigned int i=0; i<K; i++){
crc = (crc << 1) + buf[len + i];
}
return crc ^ 0xF; //invert
}

File diff suppressed because it is too large Load Diff

528
src/dmr_pdu.c Normal file
View File

@@ -0,0 +1,528 @@
/*-------------------------------------------------------------------------------
* dmr_bs.c
* DMR Data (1/2, 3/4, 1) PDU Decoding
*
* LWVMOBILE
* 2022-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
{
uint8_t slot = state->currentslot;
//check for more available flag info, etc on these prior to running
if (DMR_PDU[0] == 0x01) dmr_locn (opts, state, block_len, DMR_PDU);
else dmr_lrrp (opts, state, block_len, DMR_PDU);
//maybe one day we will have more things to do here
state->data_conf_data[slot] = 0; //flag off confirmed data after processing it
state->data_p_head[slot] = 0; //flag off prop_head data after processing it
}
//The contents of this function are mostly my reversed engineered efforts by observing DSDPlus output and matching data bytes
//combined with a few external sources such as OK-DMR for some token values and extra data values (rad and alt)
//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something)
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
{
int i;
uint16_t message_len = 0;
uint8_t slot = state->currentslot;
uint8_t blocks = state->data_header_blocks[slot];
uint8_t padding = state->data_header_padding[slot];
uint8_t lrrp_confidence = 0; //variable to increment based on number of tokens found, the more, the higher the confidence level
//source/dest and ports
uint32_t source = 0;
uint32_t dest = 0;
uint16_t port_s = 0;
uint16_t port_d = 0;
//time
uint16_t year = 0;
uint16_t month = 0;
uint16_t day = 0;
uint16_t hour = 0;
uint16_t minute = 0;
uint16_t second = 0;
//lat-long-radius-alt
uint32_t lat = 0;
uint32_t lon = 0;
uint16_t rad = 0; //or Azimuth in Circle 3D?
uint8_t alt = 0;
double lat_unit = (double)180/(double)4294967295;
double lon_unit = (double)360/(double)4294967295;
double lat_fin = 0.0; //calculated values
double lon_fin = 0.0; //calculated values
int lat_sign = 1; //positive 1, or negative 1
int lon_sign = 1; //positive 1, or negative 1
//speed -- NOTE: Velocity is Speed + Direction
uint16_t vel = 0;
double velocity = 0;
uint8_t vel_set = 0;
UNUSED(vel);
//track, direction, degrees
uint8_t degrees = 0;
uint8_t deg_set = 0;
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
// sprintf (deg_glyph, "%s", "d");
//triggered information report
uint8_t report = 0;
uint8_t pot_report = 0; //potential report by finding 0x0D and backtracking a few bytes
//start looking for tokens (using my best understanding of the ok-dmr library xml and python files)
for (i = 0; i < ( (blocks*block_len) - (padding+4) ); i++)
{
switch(DMR_PDU[i]){
case 0x0C: //LRRP_TriggeredLocationReport
if (source == 0)
{
source = (DMR_PDU[i+1] << 16 ) + (DMR_PDU[i+2] << 8) + DMR_PDU[i+3];
dest = (DMR_PDU[i+5] << 16 ) + (DMR_PDU[i+6] << 8) + DMR_PDU[i+7];
port_s = (DMR_PDU[i+8] << 8) + DMR_PDU[i+9];
port_d = (DMR_PDU[i+10] << 8) + DMR_PDU[i+11];
i += 11;
lrrp_confidence++;
}
break;
//may need more 'report' types to trigger various scenarios
//disable all but 0x1F if issues or falsing happens often
//case 0x1D: //ARRP_TriggeredInformationAnswer_NCDT
//case 0x1E: //ARRP_TriggeredInformationReport = FALSE?
//case 0x25: //ARRP_UnsolicitedInformationReport_NCDT = (0x25, True, "")
//case 0x26: //ARRP_UnsolicitedInformationReport_NCDT
//case 0x13: //LRRP_UnsolicitedLocationReport_NCDT
//case 0x15: //LRRP_LocationProtocolReport_NCDT
//case 0x21: //ARRP_TriggeredInformationStopRequest_NCDT
case 0x1F: //ARRP_TriggeredInformationReport_NCDT
if (report == 0)
{
report = DMR_PDU[i];
i += 1;
lrrp_confidence++;
}
break;
//0x0D always seems to follow 0x1F or other 'report' types two/three bytes later
case 0x0D: //message len indicator //LRRP_TriggeredLocationReport_NCDT
if (report > 0 && message_len == 0)
{
message_len = DMR_PDU[i+1];
i += 1;
lrrp_confidence++;
}
else if (message_len == 0)
{
if (i > 3)
{
if (DMR_PDU[i-3] > 0) pot_report = DMR_PDU[i-3];
if (pot_report < 0x27)
{
report = pot_report;
message_len = DMR_PDU[i+1];
i += 1;
//no lrrp_confidence on speculative reporting, but will print it as such.
}
}
}
break;
//RESULT TOKEN or Request ID!
case 0x22: //same comment as below, observed followed the message len
case 0x23: //this value has been seen after the 0x0D message len, appears to be a 2-byte value, was tripping a false on time stamp
i += 2;
break;
//answer and report tokens
case 0x51: //circle-2d
case 0x54: //circle-3d
case 0x55: //circle-3d
if (message_len > 0 && lat == 0)
{
// lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
// lon = ( ( ((DMR_PDU[i+5] & 0x7F ) << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
lat = ( ( (DMR_PDU[i+1] << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
rad = (DMR_PDU[i+9] << 8) + DMR_PDU[i+10];
i += 10;
if (lat > 0 && lon > 0) lrrp_confidence++; //would be better to set by absolute boundary (180 and 90?)
else lat = 0;
}
break;
case 0x34: //Time Interval Periodic Trigger (timestamp)
case 0x35: //Time Interval Periodic Trigger (timestamp)
if (message_len > 0 && year == 0)
{
year = (DMR_PDU[i+1] << 6) + (DMR_PDU[i+2] >> 2);
month = ((DMR_PDU[i+2] & 0x3) << 2) + ((DMR_PDU[i+3] & 0xC0) >> 6);
day = ((DMR_PDU[i+3] & 0x30) >> 1) + ((DMR_PDU[i+3] & 0x0E) >> 1);
hour = ((DMR_PDU[i+3] & 0x01) << 4) + ((DMR_PDU[i+4] & 0xF0) >> 4);
minute = ((DMR_PDU[i+4] & 0x0F) << 2) + ((DMR_PDU[i+5] & 0xC0) >> 6);
second = (DMR_PDU[i+5] & 0x3F);
i += 5;
//sanity check
if (year > 2000 && year <= 2025) lrrp_confidence++;
if (year > 2025 || year < 2000) year = 0; //needs future proofing
}
break;
case 0x66: //point-2d
if (message_len > 0 && lat == 0)
{
// lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
// lon = ( ( ((DMR_PDU[i+5] & 0x7F ) << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
lat = ( ( (DMR_PDU[i+1] << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
i += 8;
lrrp_confidence++;
}
break;
case 0x69: //point-3d
case 0x6A: //point-3d
if (message_len > 0 && lat == 0)
{
// lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
// lon = ( ( ((DMR_PDU[i+5] & 0x7F ) << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
lat = ( ( (DMR_PDU[i+1] << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
alt = DMR_PDU[i+9];
i += 9;
if (lat > 0 && lon > 0) lrrp_confidence++;
else lat = 0;
}
break;
case 0x36: //protocol-version
i += 1;
//lrrp_confidence++;
break;
//speed/velocity
case 0x70: //speed-virt
case 0x6C: //speed-hor
if (message_len > 0 && vel_set == 0)
{
vel = (DMR_PDU[i+1] << 8) + DMR_PDU[i+2]; //raw value
velocity = ( ((double)( (DMR_PDU[i+1] << 8) + DMR_PDU[i+2] )) / ( (double)255.0f)); //mps
vel_set = 1;
i += 2;
lrrp_confidence++;
}
break;
case 0x56: //direction-hor
if (message_len > 0 && deg_set == 0)
{
degrees = DMR_PDU[i+1] * 2;
deg_set = 1;
i += 1;
lrrp_confidence++;
}
break;
//below all unknown
case 0x37: //result
case 0x38: //result
case 0x39: //result 'operations error'? attributes 0x22?
case 0x6B: //unknown-uint8
case 0x65: //lev-conf
default:
//do nothing
break;
}
}
if (report && message_len > 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "\n LRRP Confidence: %d - Message Len: %d Octets", lrrp_confidence, message_len);
if (lrrp_confidence >= 3) //find the sweet magical number
{
//now we can open our lrrp file and write to it as well
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", 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)
{
fprintf (stderr, "\n");
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
}
if (report)
{
fprintf (stderr, "\n");
fprintf (stderr, " Report: 0x%02X", report);
if (report == 0x1F) fprintf (stderr, " ARRP_TriggeredInformationReport_NCDT "); //customize later when more is learned
if (report == 0x21) fprintf (stderr, " ARRP_TriggeredInformationStopRequest_NCDT ");
if (report == 0x22) fprintf (stderr, " ARRP_TriggeredInformationStopAnswer ");
if (report == 0x25) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT ");
if (report == 0x26) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT ");
if (report == 0x27) fprintf (stderr, " ARRP_InformationProtocolRequest_NCDT ");
if (report == 0x13) fprintf (stderr, " LRRP_UnsolicitedLocationReport_NCDT ");
if (report == 0x15) fprintf (stderr, " LRRP_UnsolicitedLocationReport_NCDT ");
}
if (source)
{
fprintf (stderr, "\n");
fprintf (stderr, " Source: %08d - %04d", source, port_s);
fprintf (stderr, "\n");
fprintf (stderr, " Destination: %08d - %04d", dest, port_d);
}
if (year)
{
fprintf (stderr, "\n");
fprintf (stderr, " LRRP - Time: ");
fprintf (stderr, " %04d.%02d.%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
}
if (lat)
{
fprintf (stderr, "\n");
//need to check these new calcs for accuracy accross the globe, both lat and lon
//two's compliment-ish testing on these bytes
if (lat & 0x80000000) //8
{
lat = lat & 0x7FFFFFFF;
lat_sign = -1;
// lat = 0x80000000 - lat; //not sure why this doesn't work here like it does on lon, extra bit?
}
if (lon & 0x80000000)
{
lon = lon & 0x7FFFFFFF;
lon_sign = -1;
lon = 0x80000000 - lon;
}
lat_fin = (double)lat * lat_unit * lat_sign;
lon_fin = (double)lon * lon_unit * lon_sign;
fprintf (stderr, " LRRP - Lat: %.5lf", lat_fin);
fprintf (stderr, " Lon: %.5lf", lon_fin);
fprintf (stderr, " (%.5lf, %.5lf)", lat_fin , lon_fin);
// if (opts->lrrp_file_output == 1)
// {
// fprintf (pFile, "%.5lf\t", lat_fin);
// fprintf (pFile, "%.5lf\t", lon_fin);
// }
}
//always print into the lrrp file, even if zeroes, keep alignment correct
if (opts->lrrp_file_output == 1)
{
fprintf (pFile, "%.5lf\t", lat_fin);
fprintf (pFile, "%.5lf\t", lon_fin);
//
//
}
if (rad)
{
fprintf (stderr, "\n");
fprintf (stderr, " LRRP - Radius: %dm", rad); //unsure of 'units' or calculation for radius (meters?)
}
if (alt)
{
fprintf (stderr, "\n");
fprintf (stderr, " LRRP - Altitude: %dm", alt); //unsure of 'units' or calculation for alt (meters?)
}
if (vel_set)
{
fprintf (stderr, "\n");
fprintf (stderr, " LRRP - Speed: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity));
// if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
}
//always print into the lrrp file, even if zeroes, keep alignment correct
if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
if (deg_set)
{
fprintf (stderr, "\n");
fprintf (stderr, " LRRP - Track: %d%s", degrees, deg_glyph);
// if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
}
//always print into the lrrp file, even if zeroes, keep alignment correct
if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
//close open file
if (opts->lrrp_file_output == 1)
{
fprintf (pFile, "\n");
fclose (pFile);
}
//save to string for ncurses
if (!source) source = state->dmr_lrrp_source[state->currentslot];
char velstr[20];
char degstr[20];
char lrrpstr[100];
sprintf (lrrpstr, "%s", "");
sprintf (velstr, "%s", "");
sprintf (degstr, "%s", "");
if (lat) sprintf (lrrpstr, "LRRP %0d (%lf, %lf)", source, lat_fin, lon_fin);
if (vel_set) sprintf (velstr, " %.4lf km/h", velocity * 3.6);
if (deg_set) sprintf (degstr, " %d%s ", degrees, deg_glyph);
sprintf (state->dmr_lrrp_gps[slot], "%s%s%s", lrrpstr, velstr, degstr);
}
}
else if (pot_report)
{
fprintf (stderr, "\n");
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
}
fprintf (stderr, "%s", KNRM);
}
void dmr_locn (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR_PDU[])
{
UNUSED(opts);
int i;
uint8_t slot = state->currentslot;
uint8_t blocks = state->data_header_blocks[slot];
uint8_t padding = state->data_header_padding[slot];
uint8_t source = state->dmr_lrrp_source[slot];
//flags if certain data type is present
uint8_t time = 0;
uint8_t lat = 0;
uint8_t lon = 0;
//date-time variables
uint8_t hour = 0;
uint8_t minute = 0;
uint8_t second = 0;
uint8_t year = 0;
uint8_t month = 0;
uint8_t day = 0;
//need to experiment best way to do this portion
uint8_t lat_deg = 0;
uint8_t lat_min = 0;
uint16_t lat_sec = 0;
uint8_t lon_deg = 0;
uint8_t lon_min = 0;
uint16_t lon_sec = 0;
char lat_ord[2];
char lon_ord[2];
sprintf (lat_ord, "%s", "N");
sprintf (lon_ord, "%s", "E");
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
// sprintf (deg_glyph, "%s", "d");
//more strings...
char locnstr[50];
char latstr[75];
char lonstr[75];
sprintf (locnstr, "%s", " ");
sprintf (latstr, "%s", " ");
sprintf (lonstr, "%s", " ");
//TODO: conversion to decimal format
//DD = d + (min/60) + (sec/3600)
//N is positive, E is positive?? Assuming its like a 2D plane
int lat_sign = 1; //positive 1 or negative 1
int lon_sign = 1; //positive 1 or negative 1
UNUSED2(lat_sign, lon_sign);
//start looking for specific bytes corresponding to 'letters' A (time), NSEW (ordinal directions), etc
for (i = 0; i < ( (blocks*block_len) - (padding+4) ); i++)
{
switch(DMR_PDU[i]){
case 0x41: //A -- time and date
time = 1;
hour = ((DMR_PDU[i+1] - 0x30) << 4) | (DMR_PDU[i+2] - 0x30);
minute = ((DMR_PDU[i+3] - 0x30) << 4) | (DMR_PDU[i+4] - 0x30);
second = ((DMR_PDU[i+5] - 0x30) << 4) | (DMR_PDU[i+6] - 0x30);
//think this is in day, mon, year format
day = ((DMR_PDU[i+7] - 0x30) << 4) | (DMR_PDU[i+8] - 0x30);
month = ((DMR_PDU[i+9] - 0x30) << 4) | (DMR_PDU[i+10] - 0x30);
year = ((DMR_PDU[i+11] - 0x30) << 4) | (DMR_PDU[i+12] - 0x30);
i += 12;
break;
case 0x53: //S -- South
sprintf (lat_ord, "%s", "S");
lat_sign = -1;
case 0x4E: //N -- North
lat = 1;
lat_deg = ((DMR_PDU[i+1] - 0x30) << 4) | (DMR_PDU[i+2] - 0x30);
lat_min = ((DMR_PDU[i+3] - 0x30) << 4) | (DMR_PDU[i+4] - 0x30);
lat_sec = ((DMR_PDU[i+6] - 0x30) << 12) | ((DMR_PDU[i+7] - 0x30) << 8) | ((DMR_PDU[i+8] - 0x30) << 4) | ((DMR_PDU[i+9] - 0x30) << 0);
i += 8;
break;
case 0x57: //W -- West
sprintf (lon_ord, "%s", "W");
lon_sign = -1;
case 0x45: //E -- East
lon = 1;
lon_deg = ((DMR_PDU[i+1] - 0x30) << 8) | ((DMR_PDU[i+2] - 0x30) << 4) | ((DMR_PDU[i+3] - 0x30) << 0);
lon_min = ((DMR_PDU[i+4] - 0x30) << 4) | (DMR_PDU[i+5] - 0x30);
lon_sec = ((DMR_PDU[i+7] - 0x30) << 12) | ((DMR_PDU[i+8] - 0x30) << 8) | ((DMR_PDU[i+9] - 0x30) << 4) | ((DMR_PDU[i+10] - 0x30) << 0);
i += 8;
break;
default:
//do nothing
break;
} //end switch
} //for i
if (lat && lon)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "\n LOCN Report - Source: [%d]\n", source);
if (time) fprintf (stderr, " 20%02X/%02X/%02X %02X:%02X:%02X ", year, month, day, hour, minute, second);
fprintf (stderr, "Lat: %s %02X%s%02X\"%04X' Lon: %s %02X%s%02X\"%04X' ", lat_ord, lat_deg, deg_glyph, lat_min, lat_sec, lon_ord, lon_deg, deg_glyph, lon_min, lon_sec);
//string manip for ncurses terminal display
sprintf (locnstr, "LOCN %d ", source);
sprintf (latstr, "%s %02X%s%02X\"%04X' ", lat_ord, lat_deg, deg_glyph, lat_min, lat_sec);
sprintf (lonstr, "%s %02X%s%02X\"%04X' ", lon_ord, lon_deg, deg_glyph, lon_min, lon_sec);
sprintf (state->dmr_lrrp_gps[slot], "%s%s%s", locnstr, latstr, lonstr);
}
}

180
src/dmr_pi.c Normal file
View File

@@ -0,0 +1,180 @@
/*-------------------------------------------------------------------------------
* dmr_pi.c
* DMR Privacy Indicator and LFSR Function
*
* LFSR code courtesy of https://github.com/mattames/LFSR/
*
* LWVMOBILE
* 2022-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
{
UNUSED2(opts, CRCCorrect);
if((IrrecoverableErrors == 0))
{
//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];
state->payload_keyid = PI_BYTE[2];
state->payload_mi = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
if (state->payload_algid < 0x26)
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 1");
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
//Anytone RC4 Shim
if (state->payload_algid == 0x01)
{
fprintf (stderr, " Anytone (0x01)");
state->payload_algid = 0x21;
}
fprintf (stderr, "%s ", KNRM);
if (state->payload_algid != 0x21)
{
fprintf (stderr, "\n");
LFSR64 (state);
}
}
if (state->payload_algid >= 0x26)
{
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_mi = 0;
}
}
if (state->currentslot == 1)
{
state->payload_algidR = PI_BYTE[0];
state->payload_keyidR = PI_BYTE[2];
state->payload_miR = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
if (state->payload_algidR < 0x26)
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 2");
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
//Anytone RC4 Shim
if (state->payload_algidR == 0x01)
{
fprintf (stderr, " Anytone (0x01)");
state->payload_algidR = 0x21;
}
fprintf (stderr, "%s ", KNRM);
if (state->payload_algidR != 0x21)
{
fprintf (stderr, "\n");
LFSR64 (state);
}
}
if (state->payload_algidR >= 0x26)
{
state->payload_algidR = 0;
state->payload_keyidR = 0;
state->payload_miR = 0;
}
}
}
}
void LFSR(dsd_state * state)
{
int lfsr = 0;
if (state->currentslot == 0)
{
lfsr = state->payload_mi;
}
else lfsr = state->payload_miR;
uint8_t cnt = 0;
for(cnt=0;cnt<32;cnt++)
{
// Polynomial is C(x) = x^32 + x^4 + x^2 + 1
int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1;
lfsr = (lfsr << 1) | (bit);
}
if (state->currentslot == 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
fprintf(stderr, " MI: 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_mi = lfsr;
}
if (state->currentslot == 1)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
fprintf(stderr, " MI: 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_miR = lfsr;
}
}
void LFSR64(dsd_state * state)
{
{
unsigned long long int lfsr = 0;
if (state->currentslot == 0)
{
lfsr = (uint64_t) state->payload_mi;
}
else lfsr = (uint64_t) state->payload_miR;
uint8_t cnt = 0;
for(cnt=0;cnt<32;cnt++)
{
unsigned long long int bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
lfsr = (lfsr << 1) | bit;
}
if (state->currentslot == 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
fprintf (stderr, " MI: 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
}
if (state->currentslot == 1)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
fprintf (stderr, " MI: 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
}
}
}

View File

@@ -1,395 +0,0 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "dmr_const.h"
#include "p25p1_check_hdu.h"
void ProcessDMR (dsd_opts * opts, dsd_state * state)
{
uint32_t i, j;
uint32_t Frame;
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL;
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL;
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameRC = NULL; //Reverse Test for MS Backwards
int *errs;
int *errs2;
unsigned long long int k;
int x;
k = 0;
TSVoiceSupFrameL = &state->TS1SuperFrame;
TSVoiceSupFrameR = &state->TS2SuperFrame;
int Pr[256] = {
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
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,
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,
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255
};
if ( (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
(state->currentslot == 0 && state->K > 0 && state->M == 1) )
{
fprintf (stderr, "%s", KYEL);
fprintf(stderr, " PrK %lld", state->K);
fprintf (stderr, "%s", KNRM);
k = Pr[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
for(Frame = 0; Frame < 6; Frame++)
{
for(i = 0; i < 3; i++)
{
for(j = 0; j < 48; j++)
{
x = ( ((k << j) & 0x800000000000) >> 47 );
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x;
}
}
}
}
if ( (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
(state->currentslot == 1 && state->K > 0 && state->M == 1) )
{
fprintf (stderr, "%s", KYEL);
fprintf(stderr, " PrK %lld", state->K);
fprintf (stderr, "%s", KNRM);
k = Pr[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
for(Frame = 0; Frame < 6; Frame++)
{
for(i = 0; i < 3; i++)
{
for(j = 0; j < 48; j++)
{
x = ( ((k << j) & 0x800000000000) >> 47 );
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x;
}
}
}
}
if ( (state->currentslot == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
(state->currentslot == 0 && state->K1 > 0 && state->M == 1) )
{
int pos = 0;
unsigned long long int k1 = state->K1;
unsigned long long int k2 = state->K2;
unsigned long long int k3 = state->K3;
unsigned long long int k4 = state->K4;
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
fprintf(stderr, " SPT %010llX", k1);
int T_Key[256] = {0};
int pN[882] = {0};
int len = 0;
if (k2 == 0)
{
len = 39;
k1 = k1 << 24;
}
if (k2 != 0)
{
len = 127;
fprintf(stderr, " %016llX", k2);
}
if (k4 != 0)
{
len = 255;
fprintf(stderr, " %016llX", k3);
fprintf(stderr, " %016llX", k4);
}
fprintf (stderr, "%s", KNRM);
for (i = 0; i < 64; i++)
{
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
}
for (i = 0; i < 882; i++)
{
pN[i] = T_Key[pos];
pos++;
if (pos > len)
{
pos = 0;
}
}
pos = 0;
for(Frame = 0; Frame < 6; Frame++)
{
for(i = 0; i < 3; i++)
{
for(j = 0; j < 49; j++)
{
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos];
pos++;
}
}
}
}
if ( (state->currentslot == 1 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
(state->currentslot == 1 && state->K1 > 0 && state->M == 1) )
{
int pos = 0;
unsigned long long int k1 = state->K1;
unsigned long long int k2 = state->K2;
unsigned long long int k3 = state->K3;
unsigned long long int k4 = state->K4;
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
fprintf(stderr, " SPT %010llX", k1);
int T_Key[256] = {0};
int pN[882] = {0};
int len = 0;
if (k2 == 0)
{
len = 39;
k1 = k1 << 24;
}
if (k2 != 0)
{
len = 127;
fprintf(stderr, " %016llX", k2);
}
if (k4 != 0)
{
len = 255;
fprintf(stderr, " %016llX", k3);
fprintf(stderr, " %016llX", k4);
}
fprintf (stderr, "%s", KNRM);
for (i = 0; i < 64; i++)
{
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
}
for (i = 0; i < 882; i++)
{
pN[i] = T_Key[pos];
pos++;
if (pos > len)
{
pos = 0;
}
}
pos = 0;
for(Frame = 0; Frame < 6; Frame++)
{
for(i = 0; i < 3; i++)
{
for(j = 0; j < 49; j++)
{
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos];
pos++;
}
}
}
}
if (state->currentslot == 0)
{
for(Frame = 0; Frame < 6; Frame++) //6
{
/* 1 DMR frame contains 3 AMBE voice samples */
for(i = 0; i < 3; i++)
{
errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
state->errs = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
state->errs2 = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->payload == 1)
{
PrintAMBEData(opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
}
//quick enc toggle to determine whether or not to play enc traffic
int enc_bit = 0;
enc_bit = (state->dmr_so >> 6) & 0x1;
if (enc_bit == 1)
{
state->dmr_encL = 1;
}
else state->dmr_encL = 0;
if (state->K != 0 || state->K1 != 0)
{
state->dmr_encL = 0;
}
//quick test to determine whether or not to run the next few steps below
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
{
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
}
state->debug_audio_errors += *errs2;
processAudio(opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1) //opts->audio_out == 1
{
playSynthesizedVoice (opts, state);
}
} //second bracket for the test enc condition
} /* End for(i = 0; i < 3; i++) */
} /* End for(Frame = 0; Frame < 6; Frame++) */
} //End if Current Slot == 0
if (state->currentslot == 1)
{
for(Frame = 0; Frame < 6; Frame++)
{
/* 1 DMR frame contains 3 AMBE voice samples */
for(i = 0; i < 3; i++)
{
errs = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
errs2 = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->payload == 1)
{
PrintAMBEData(opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
}
//quick enc toggle to determine whether or not to play enc traffic
int enc_bit = 0;
enc_bit = (state->dmr_soR >> 6) & 0x1;
if (enc_bit == 1)
{
state->dmr_encR = 1;
}
else state->dmr_encR = 0;
if (state->K != 0 || state->K1 != 0)
{
state->dmr_encR = 0;
}
//quick test to determine whether or not to run the next few steps below
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
{
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
}
state->debug_audio_errors += *errs2;
if (opts->audio_out == 1)
{
processAudio(opts, state);
}
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
} /* End for(i = 0; i < 3; i++) */
} /* End for(Frame = 0; Frame < 6; Frame++) */
} //End if Current Slot == 1
} /* End ProcessDMR */
/* End of file */

File diff suppressed because it is too large Load Diff

440
src/dmr_utils.c Normal file
View File

@@ -0,0 +1,440 @@
//DMR CRC/Utility Functions
//Original File - dmr_sync.c
//ConvertBitIntoBytes, ComputeCrcCCITT, ComputeCrc5Bit, ComputeAndCorrectFullLinkControlCrc, CRC32, CRC9
//Original Source - https://github.com/LouisErigHerve/dsd
//Additional Functions
//Hamming17123, crc7, crc8, crc8ok functions
//Original Souce - https://github.com/boatbod/op25
#include "dsd.h"
//modified to accept variable payload size and len
uint16_t ComputeCrcCCITT16d(const uint8_t buf[], uint8_t len)
{
uint32_t i;
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
/* Polynomial x^16 + x^12 + x^5 + 1
* Normal = 0x1021
* Reciprocal = 0x0811
* Reversed = 0x8408
* Reversed reciprocal = 0x8810 */
uint16_t Polynome = 0x1021;
for(i = 0; i < len; i++)
{
if(((CRC >> 15) & 1) ^ (buf[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
/* Invert the CRC */
CRC ^= 0xFFFF;
/* Return the CRC */
return CRC;
} /* End ComputeCrcCCITTd() */
// A Hamming (17,12,3) Check for completed SLC message
bool Hamming17123(uint8_t* d)
{
// Calculate the checksum this column should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
// Compare these with the actual bits
unsigned char n = 0x00U;
n |= (c0 != d[12]) ? 0x01U : 0x00U;
n |= (c1 != d[13]) ? 0x02U : 0x00U;
n |= (c2 != d[14]) ? 0x04U : 0x00U;
n |= (c3 != d[15]) ? 0x08U : 0x00U;
n |= (c4 != d[16]) ? 0x10U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[12] = !d[12]; return true;
case 0x02U: d[13] = !d[13]; return true;
case 0x04U: d[14] = !d[14]; return true;
case 0x08U: d[15] = !d[15]; return true;
case 0x10U: d[16] = !d[16]; return true;
// Data bit errors
case 0x1BU: d[0] = !d[0]; return true;
case 0x1FU: d[1] = !d[1]; return true;
case 0x17U: d[2] = !d[2]; return true;
case 0x07U: d[3] = !d[3]; return true;
case 0x0EU: d[4] = !d[4]; return true;
case 0x1CU: d[5] = !d[5]; return true;
case 0x11U: d[6] = !d[6]; return true;
case 0x0BU: d[7] = !d[7]; return true;
case 0x16U: d[8] = !d[8]; return true;
case 0x05U: d[9] = !d[9]; return true;
case 0x0AU: d[10] = !d[10]; return true;
case 0x14U: d[11] = !d[11]; return true;
// No bit errors
case 0x00U: return true;
// Unrecoverable errors
default: return false;
}
}
uint8_t crc8(uint8_t bits[], unsigned int len)
{
uint8_t crc=0;
unsigned int K = 8;
uint8_t poly[9] = {1,0,0,0,0,0,1,1,1}; // crc8 poly
uint8_t buf[256];
if (len+K > sizeof(buf)) {
//fprintf (stderr, "crc8: buffer length %u exceeds maximum %lu\n", len+K, sizeof(buf));
return 0;
}
memset (buf, 0, sizeof(buf));
for (unsigned int i=0; i<len; i++){
buf[i] = bits[i];
}
for (unsigned int i=0; i<len; i++)
if (buf[i])
for (unsigned int j=0; j<K+1; j++)
buf[i+j] ^= poly[j];
for (unsigned int i=0; i<K; i++){
crc = (crc << 1) + buf[len + i];
}
return crc;
}
bool crc8_ok(uint8_t bits[], unsigned int len)
{
uint16_t crc = 0;
for (unsigned int i=0; i < 8; i++) {
crc = (crc << 1) + bits[len+i];
}
return (crc == crc8(bits,len));
}
uint8_t crc7(uint8_t bits[], unsigned int len)
{
uint8_t crc=0;
unsigned int K = 7;
//G7(x) = x7 + x5 + x2 + x + 1 check poly below for correct (dmr rc crc7)
uint8_t poly[8] = {1,0,1,0,0,1,1,1}; // crc7 poly
uint8_t buf[256];
if (len+K > sizeof(buf)) {
// fprintf (stderr, "crc8: buffer length %u exceeds maximum %lu\n", len+K, sizeof(buf));
return 0;
}
memset (buf, 0, sizeof(buf));
for (unsigned int i=0; i<len; i++){
buf[i] = bits[i];
}
for (unsigned int i=0; i<len; i++)
if (buf[i])
for (unsigned int j=0; j<K+1; j++)
buf[i+j] ^= poly[j];
for (unsigned int i=0; i<K; i++){
crc = (crc << 1) + buf[len + i];
}
return crc;
}
/*
* @brief : This function compute the CRC-CCITT of the DMR data
* by using the polynomial x^16 + x^12 + x^5 + 1
*
* @param Input : A buffer pointer of the DMR data (80 bytes)
*
* @return The 16 bit CRC
*/
uint16_t ComputeCrcCCITT(uint8_t * DMRData)
{
uint32_t i;
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
/* Polynomial x^16 + x^12 + x^5 + 1
* Normal = 0x1021
* Reciprocal = 0x0811
* Reversed = 0x8408
* Reversed reciprocal = 0x8810 */
uint16_t Polynome = 0x1021;
for(i = 0; i < 80; i++)
{
if(((CRC >> 15) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
/* Invert the CRC */
CRC ^= 0xFFFF;
/* Return the CRC */
return CRC;
} /* End ComputeCrcCCITT() */
/*
* @brief : This function compute the CRC-24 bit of the full
* link control by using the Reed-Solomon(12,9) FEC
*
* @param FullLinkControlDataBytes : A buffer pointer of the DMR data bytes (12 bytes)
*
* @param CRCComputed : A 32 bit pointer where the computed CRC 24-bit will be stored
*
* @param CRCMask : The 24 bit CRC mask to apply
*
* @return 0 = CRC error
* 1 = CRC is correct
*/
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask)
{
uint32_t i;
rs_12_9_codeword_t VoiceLCHeaderStr;
rs_12_9_poly_t syndrome;
uint8_t errors_found = 0;
rs_12_9_correct_errors_result_t result = RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND;
uint32_t CrcIsCorrect = 0;
for(i = 0; i < 12; i++)
{
VoiceLCHeaderStr.data[i] = FullLinkControlDataBytes[i];
/* Apply CRC mask on each 3 last bytes
* of the full link control */
if(i == 9)
{
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 16);
}
else if(i == 10)
{
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 8);
}
else if(i == 11)
{
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask);
}
else
{
/* Nothing to do */
}
}
/* Check and correct the full link LC control with Reed Solomon (12,9) FEC */
rs_12_9_calc_syndrome(&VoiceLCHeaderStr, &syndrome);
if(rs_12_9_check_syndrome(&syndrome) != 0) result = rs_12_9_correct_errors(&VoiceLCHeaderStr, &syndrome, &errors_found);
/* Reconstitue the CRC */
*CRCComputed = (uint32_t)((VoiceLCHeaderStr.data[9] << 16) & 0xFF0000);
*CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[10] << 8) & 0x00FF00);
*CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[11] << 0) & 0x0000FF);
if((result == RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND) ||
(result == RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED))
{
//fprintf(stderr, "CRC OK : 0x%06X\n", *CRCComputed);
CrcIsCorrect = 1;
/* Reconstitue full link control data after FEC correction */
for(i = 0; i < 12; i++)
{
FullLinkControlDataBytes[i] = VoiceLCHeaderStr.data[i];
/* Apply CRC mask on each 3 last bytes
* of the full link control */
if(i == 9)
{
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 16);
}
else if(i == 10)
{
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 8);
}
else if(i == 11)
{
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask);
}
else
{
/* Nothing to do */
}
}
}
else
{
//fprintf(stderr, "CRC ERROR : 0x%06X\n", *CRCComputed);
CrcIsCorrect = 0;
}
/* Return the CRC status */
return CrcIsCorrect;
} /* End ComputeAndCorrectFullLinkControlCrc() */
/*
* @brief : This function compute the 5 bit CRC of the DMR voice burst data
* See ETSI TS 102 361-1 chapter B.3.11
*
* @param Input : A buffer pointer of the DMR data (72 bytes)
*
* @return The 5 bit CRC
*/
uint8_t ComputeCrc5Bit(uint8_t * DMRData)
{
uint32_t i, j, k;
uint8_t Buffer[9];
uint32_t Sum;
uint8_t CRC = 0;
/* Convert the 72 bit into 9 bytes */
k = 0;
for(i = 0; i < 9; i++)
{
Buffer[i] = 0;
for(j = 0; j < 8; j++)
{
Buffer[i] = Buffer[i] << 1;
Buffer[i] = Buffer[i] | DMRData[k++];
}
}
/* Add all 9 bytes */
Sum = 0;
for(i = 0; i < 9; i++)
{
Sum += (uint32_t)Buffer[i];
}
/* Sum MOD 31 = CRC */
CRC = (uint8_t)(Sum % 31);
/* Return the CRC */
return CRC;
} /* End ComputeCrc5Bit() */
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
{
uint64_t Output = 0;
uint32_t i;
for(i = 0; i < BitLength; i++)
{
Output <<= 1;
Output |= (uint64_t)(BufferIn[i] & 1);
}
return Output;
} /* End ConvertBitIntoBytes() */
/*
* @brief : This function compute the CRC-9 of the DMR data
* by using the polynomial x^9 + x^6 + x^4 + x^3 + 1
*
* @param Input : A buffer pointer of the DMR data (80 bytes)
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @param NbData : The number of bit to compute
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @return The 9 bit CRC
*/
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData)
{
uint32_t i;
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
/* Polynomial x^9 + x^6 + x^4 + x^3 + 1
* Normal = 0x059
* Reciprocal = 0x134
* Reversed reciprocal = 0x12C */
uint16_t Polynome = 0x059;
for(i = 0; i < NbData; i++)
{
if(((CRC >> 8) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
/* Conserve only the 9 LSBs */
CRC &= 0x01FF;
/* Invert the CRC */
CRC ^= 0x01FF;
/* Return the CRC */
return CRC;
} /* End ComputeCrc9Bit() */
/*
* @brief : This function compute the CRC-32 of the DMR data
* by using the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
*
* @param Input : A buffer pointer of the DMR data (80 bytes)
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @param NbData : The number of bit to compute
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @return The 32 bit CRC
*/
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData)
{
uint32_t i;
uint32_t CRC = 0x00000000; /* Initialization value = 0x00000000 */
/* Polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
* Normal = 0x04C11DB7
* Reversed = 0xEDB88320
* Reciprocal = 0xDB710641
* Reversed reciprocal = 0x82608EDB */
uint32_t Polynome = 0x04C11DB7;
for(i = 0; i < NbData; i++)
{
if(((CRC >> 31) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
//for whatever reason, we get the CRC returned in a reversed byte order (MSO LSO b***s***)
uint32_t a, b, c, d;
a = b = c = d = 0;
a = (CRC & 0xFF) << 24;
b = (CRC & 0xFF00) >> 8;
b = b << 16;
c = (CRC & 0xFF0000) >> 16;
c = c << 8;
d = (CRC & 0xFF000000) >> 24;
CRC = a + b + c + d;
/* Return the CRC */
return CRC;
} /* End ComputeCrc32Bit() */

View File

@@ -1,660 +0,0 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
#include "dmr_const.h"
void processDMRvoice (dsd_opts * opts, dsd_state * state)
{
// extracts AMBE frames from DMR frame
int i, j, k, l, dibit;
int *dibit_p;
char ambe_fr[4][24] = {0};
char ambe_fr2[4][24] = {0};
char ambe_fr3[4][24] = {0};
const int *w, *x, *y, *z;
char sync[25];
char syncdata[48];
char cachdata[13] = {0};
int mutecurrentslot;
int msMode;
char cc[4];
unsigned char EmbeddedSignalling[16];
unsigned int EmbeddedSignallingOk;
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];12
#endif
/* Init the superframe buffers */
memset(&state->TS1SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t));
memset(&state->TS2SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t));
/* Init the color code status */
state->color_code_ok = 0;
mutecurrentslot = 0;
msMode = 0;
dibit_p = state->dibit_buf_p - 144;
for(j = 0; j < 6; j++)
{
// 2nd half of previous slot
for(i = 0; i < 54; i++)
{
if(j > 0)
{
dibit = getDibit(opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
}
// CACH
for(i = 0; i < 12; i++)
{
if(j > 0)
{
dibit = getDibit(opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
cachdata[i] = dibit;
if(i == 2)
{
/* Change the current slot only if we are in relayed mode (not in direct mode) */
if(state->directmode == 0) state->currentslot = (1 & (dibit >> 1)); // bit 1
if(state->currentslot == 0)
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot2light[0] = ' ';
state->slot2light[6] = ' ';
}
else
{
state->slot2light[0] = '[';
state->slot2light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
}
}
cachdata[12] = 0;
//set state-dmrburstL and R here to a value for ncurses
if (state->currentslot == 0)
{
state->dmrburstL = 16; //use 16 for Voice?
}
if (state->currentslot == 1)
{
state->dmrburstR = 16; //Use 16 for Voice?
}
#ifdef DMR_DUMP
k = 0;
for(i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
fprintf(stderr, "%s ", cachbits);
#endif
// current slot frame 1
w = rW;
x = rX;
y = rY;
z = rZ;
k = 0;
for(i = 0; i < 36; i++)
{
if(j > 0)
{
dibit = getDibit(opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
/* Save the current frame in the appropriate superframe buffer */
if(state->currentslot == 0)
{
/* Time slot 1 superframe buffer filling => RAW voice bit */
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0
}
else
{
/* Time slot 2 superframe buffer filling => RAW voice bit */
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0
}
w++;
x++;
y++;
z++;
}
// current slot frame 2 first half
w = rW;
x = rX;
y = rY;
z = rZ;
k = 0;
for(i = 0; i < 18; i++)
{
if(j > 0)
{
dibit = getDibit(opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
/* Save the current frame in the appropriate superframe buffer */
if(state->currentslot == 0)
{
/* Time slot 1 superframe buffer filling => RAW voice bit */
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
}
else
{
/* Time slot 2 superframe buffer filling => RAW voice bit */
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
}
w++;
x++;
y++;
z++;
}
l = 0;
// signaling data or sync
for(i = 0; i < 24; i++)
{
if(j > 0)
{
dibit = getDibit(opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
syncdata[(2*i)+1] = (1 & dibit); // bit 0
sync[i] = (dibit | 1) + 48;
/* Save the current frame in the appropriate superframe buffer */
if(state->currentslot == 0)
{
/* Time slot 1 superframe buffer filling => SYNC data */
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0
}
else
{
/* Time slot 2 superframe buffer filling => SYNC data */
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0
}
}
sync[24] = 0;
/* Copy the Embedded signaling (1st part) */
for(i = 0; i < 8; i++)
{
EmbeddedSignalling[i] = syncdata[i];
}
/* Copy the Embedded signaling (2nd part) */
for(i = 0; i < 8; i++)
{
EmbeddedSignalling[i + 8] = syncdata[i + 40];
}
/* Check and correct the SlotType (apply Golay(20,8) FEC check) */
if(QR_16_7_6_decode(EmbeddedSignalling)) EmbeddedSignallingOk = 1;
else EmbeddedSignallingOk = 0;
/* Get the color code */
cc[0] = EmbeddedSignalling[0];
cc[1] = EmbeddedSignalling[1];
cc[2] = EmbeddedSignalling[2];
cc[3] = EmbeddedSignalling[3];
/* The color code is normally the same for all
* 6 received voice frame, so in case of error
* do not store it except if the last SYNC frame
* has been received. */
if(EmbeddedSignallingOk || ((state->color_code_ok == 0) && (j == 5)))
{
/* Save the color code */
state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]);
state->color_code_ok = EmbeddedSignallingOk;
}
/* Save the Power Control (PI) indicator */
state->PI = (unsigned int)EmbeddedSignalling[4];
state->PI_ok = EmbeddedSignallingOk;
/* Save the Link Control Start Stop (LCSS) indicator */
state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
state->LCSS_ok = EmbeddedSignallingOk;
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
mutecurrentslot = 1;
state->directmode = 0;
if(state->currentslot == 0)
{
sprintf(state->slot1light, "[slot1]");
}
else
{
sprintf(state->slot2light, "[slot2]");
}
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)
{
mutecurrentslot = 1;
state->currentslot = 0;
state->directmode = 1; /* Direct mode */
sprintf(state->slot1light, "[sLoT1]");
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
{
mutecurrentslot = 1;
state->currentslot = 1;
state->directmode = 1; /* Direct mode */
sprintf(state->slot1light, "[sLoT2]");
}
else if((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) ) //|| (strcmp (sync, DMR_MS_VOICE_SYNC) == 0))
{
mutecurrentslot = 0;
state->directmode = 0;
if(state->currentslot == 0)
{
sprintf(state->slot1light, "[SLOT1]");
}
else
{
sprintf(state->slot2light, "[SLOT2]");
}
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0)
{
mutecurrentslot = 0;
state->currentslot = 0;
state->directmode = 1; /* Direct mode */
sprintf(state->slot1light, "[sLoT1]");
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
{
mutecurrentslot = 0;
state->currentslot = 1;
state->directmode = 1; /* Direct mode */
sprintf(state->slot2light, "[sLoT2]");
}
#ifdef DMR_DUMP
k = 0;
for(i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
fprintf(stderr, "%s ", syncbits);
#endif
// current slot frame 2 second half
for(i = 0; i < 18; i++)
{
dibit = getDibit(opts, state);
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
/* Save the current frame in the appropriate superframe buffer */
if(state->currentslot == 0)
{
/* Time slot 1 superframe buffer filling => RAW voice bit */
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
}
else
{
/* Time slot 2 superframe buffer filling */
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
}
w++;
x++;
y++;
z++;
}
if(mutecurrentslot == 0)
{
if(state->firstframe == 1)
{ // we don't know if anything received before the first sync after no carrier is valid
state->firstframe = 0;
}
else
{
//processMbeFrame (opts, state, NULL, ambe_fr, NULL);
//processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
}
}
// current slot frame 3
w = rW;
x = rX;
y = rY;
z = rZ;
k = 0;
for(i = 0; i < 36; i++)
{
dibit = getDibit(opts, state);
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
/* Save the current frame in the appropriate superframe buffer */
if(state->currentslot == 0)
{
/* Time slot 1 superframe buffer filling => RAW voice bit */
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0
}
else
{
/* Time slot 2 superframe buffer filling => RAW voice bit */
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0
}
w++;
x++;
y++;
z++;
}
if(mutecurrentslot == 0)
{
//processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
// CACH
for(i = 0; i < 12; i++)
{
dibit = getDibit(opts, state);
cachdata[i] = dibit;
}
cachdata[12] = 0;
#ifdef DMR_DUMP
k = 0;
for(i = 0; i < 12; i++)
{
dibit = cachdata[i];
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
cachbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
cachbits[24] = 0;
fprintf(stderr, "%s ", cachbits);
#endif
// next slot
skipDibit (opts, state, 54);
// signaling data or sync
for(i = 0; i < 24; i++)
{
dibit = getDibit(opts, state);
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1))
{
state->directmode = 0;
if(state->currentslot == 0)
{
sprintf(state->slot2light, " slot2 ");
}
else
{
sprintf(state->slot1light, " slot1 ");
}
}
else if(strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
{
state->directmode = 0;
if(state->currentslot == 0)
{
sprintf(state->slot2light, " SLOT2 ");
}
else
{
sprintf(state->slot1light, " SLOT1 ");
}
}
else if((strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0))
{
state->currentslot = 0;
state->directmode = 1; /* Direct mode */
sprintf(state->slot1light, " sLoT1 ");
}
else if((strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0))
{
state->currentslot = 1;
state->directmode = 1; /* Direct mode */
sprintf(state->slot1light, " sLoT2 ");
}
#ifdef DMR_DUMP
k = 0;
for(i = 0; i < 24; i++)
{
dibit = syncdata[i];
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
k++;
syncbits[k] = (1 & dibit) + 48; // bit 0
k++;
}
syncbits[48] = 0;
fprintf(stderr, "%s ", syncbits);
#endif
if(j == 5) //j == 5
{
// 2nd half next slot
skipDibit (opts, state, 54);
// CACH
skipDibit (opts, state, 12);
// first half current slot
skipDibit (opts, state, 54);
}
/* Extract the 49 bits AMBE of the voice frame */
if(state->currentslot == 0)
{
/* 3 x 49 bit of AMBE sample per voice frame => Slot 1buffer here */
for(i = 0; i < 3; i++)
{
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
mbe_demodulateAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
&(state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
}
}
else
{
/* 3 x 49 bit of AMBE sample per voice frame => Slot 2 buffer here */
for(i = 0; i < 3; i++)
{
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
mbe_demodulateAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
&(state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
}
}
} /* End for(j = 0; j < 6; j++) */
if(opts->errorbars == 1)
{
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
/* Print the color code */
fprintf (stderr, "%s", KCYN);
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
fprintf (stderr, "%s", KNRM);
//if(state->color_code_ok) fprintf(stderr, "(OK) |");
if(state->color_code_ok)
{
fprintf(stderr, "| (CRC OK ) |"); //add line break
state->dmr_color_code = state->color_code; //set here when voice? otherwise is set off of idle.
}
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, "| (CRC ERR) |"); //add line break
fprintf (stderr, "%s", KNRM);
}
fprintf(stderr, " VOICE ");
}
/* Perform the SYNC DMR data embedded decoding */
ProcessVoiceBurstSync(opts, state);
/* Perform the DMR voice decoding */
ProcessDMR(opts, state);
//LFSR if required, change condition?
if ( (state->currentslot == 0 && state->payload_algid == 0x21 ) || //&& opts->payload == 1
(state->currentslot == 1 && state->payload_algidR == 0x21 ) ) //&& opts->payload == 1
{
LFSR(state);
}
if(opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
} /* End processDMRvoice() */

View File

@@ -24,11 +24,18 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
uint8_t CCH[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0}; uint8_t CCH[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDescrambled[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0}; uint8_t CCHDescrambled[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDeInterleaved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0}; uint8_t CCHDeInterleaved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDataHammingCorrected[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48] = {0}; uint8_t CCHDataHammingCorrected[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48];
uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0}; uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
memset (CCHDataHammingCorrected, 1, sizeof(CCHDataHammingCorrected));
memset (CCHDataCRC, 1, sizeof(CCHDataCRC));
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
memset (CCHDataCRCComputed, 0, sizeof(CCHDataCRCComputed));
uint8_t CC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE / 2][24] = {0}; uint8_t CC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE / 2][24] = {0};
char ambe_fr[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][4][24] = {0}; char ambe_fr[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][4][24];
memset (ambe_fr, 0, sizeof (ambe_fr));
const int *w, *x, *y, *z; const int *w, *x, *y, *z;
uint32_t ScramblerLFSR = 0; uint32_t ScramblerLFSR = 0;
bool correctable = true; bool correctable = true;
@@ -46,20 +53,10 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
uint32_t CCH_EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE]; uint32_t CCH_EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE]; uint32_t CCH_Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE]; uint32_t CCH_SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t *errs;
uint32_t *errs2;
uint8_t AmbeBitDescrambled[49] = {0};
uint32_t ScramblerKey = 0;
uint32_t PartOfSuperFrame = 0; uint32_t PartOfSuperFrame = 0;
uint32_t VoiceFrameFlag = 1; /* We consider the current frame as a voice frame */
uint32_t AttachedDataFlag = 0;
uint8_t CalledID[8] = {0}; uint8_t CalledID[8] = {0};
uint8_t CallingID[8] = {0}; uint8_t CallingID[8] = {0};
UNUSED(PartOfSuperFrame);
if (opts->errorbars == 1)
{
//fprintf(stderr, "VOICE e:");
}
/* First CCH (Control CHannel) - 72 bit */ /* First CCH (Control CHannel) - 72 bit */
k = 0; k = 0;
@@ -76,7 +73,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
CCH[0][(i * 2)] = (1 & (dibit >> 1)); // bit 1 CCH[0][(i * 2)] = (1 & (dibit >> 1)); // bit 1
CCH[0][(i * 2) + 1] = (1 & dibit); // bit 0 CCH[0][(i * 2) + 1] = (1 & dibit); // bit 0
} }
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */ /* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
@@ -148,9 +144,6 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */ /* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
//Sync issues occur when FS2 occurs immediatly after the 4th rep, so cutting of 4 early to gain constant resync
//probably can't resync fast enough when the next sync starts immediately after the 4th rep of 36 dibits
//consider writing a method that will loop this entire process based on the frame numbering found inside the CCH info, is that possible?
k = 0; k = 0;
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
{ {
@@ -177,18 +170,10 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
x++; x++;
y++; y++;
z++; z++;
if (j == 3 && i == 28) //find sweet spot to cut off early
{
i = 40; //break early so FS2 sync can resync
}
} }
} }
/* Initialize the Hamming (12,8) error code detection
* Not needed because it has already been done
* in the "InitAllFecFunction()" function */
//Hamming_12_8_init();
/* Decoding all CCH (Control CHannel) */ /* Decoding all CCH (Control CHannel) */
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++) for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{ {
@@ -209,22 +194,8 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
if(HammingCorrectable[i][j] == false) correctable = false; if(HammingCorrectable[i][j] == false) correctable = false;
} }
if(correctable) if(correctable) HammingOk[i] = 1;
{ else HammingOk[i] = 0;
//fprintf(stderr, "CCH data corrected successfully\n");
HammingOk[i] = 1;
}
else
{
//fprintf(stderr, "ERROR !!! CCH data contains uncorrectable bit\n");
HammingOk[i] = 0;
}
/* Reconstitute the 7 bit CRC */ /* Reconstitute the 7 bit CRC */
CCHDataCRC[i] = 0; CCHDataCRC[i] = 0;
@@ -239,24 +210,8 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
/* Compute the 7 bit CRC */ /* Compute the 7 bit CRC */
CCHDataCRCComputed[i] = CRC7BitdPMR(CCHDataHammingCorrected[i], 41); CCHDataCRCComputed[i] = CRC7BitdPMR(CCHDataHammingCorrected[i], 41);
if(CCHDataCRC[i] == CCHDataCRCComputed[i]) if(CCHDataCRC[i] == CCHDataCRCComputed[i]) CrcOk[i] = 1;
{ else CrcOk[i] = 0;
//fprintf(stderr, "Good CCH CRCs ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
// CCHDataCRC[i], CCHDataCRCComputed[i]);
CrcOk[i] = 1;
}
else
{
//fprintf(stderr, "ERROR !!! CCH CRCs are different ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
// CCHDataCRC[i], CCHDataCRCComputed[i]);
CrcOk[i] = 0;
}
/* Fill the frame number */ /* Fill the frame number */
CCH_FrameNumber[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][0], 2); CCH_FrameNumber[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][0], 2);
@@ -302,45 +257,18 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
CallingID[7] = '\0'; CallingID[7] = '\0';
/* Print Hamming debug info */
//fprintf(stderr, " | ");
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
//fprintf(stderr, "Hamming[%u]=", i);
for(j = 0; j < 6; j++)
{
//if(HammingCorrectable[i][j]) fprintf(stderr, "1");
//else fprintf(stderr, "0");
}
//fprintf(stderr, " HammingOk[%u]=%u", i, HammingOk[i]);
//fprintf(stderr, " CrcOk[%u]=%u", i, CrcOk[i]);
//fprintf(stderr, " Bit[%u]=", i);
//for(j = 0; j < 7; j++)
//{
// if(CCHDataHammingCorrected[i][j + 41]) fprintf(stderr, "1");
// else fprintf(stderr, "0");
//}
//fprintf(stderr, " CRCrec=0x%02X CRCcomp=0x%02X", CCHDataCRC[i], CCHDataCRCComputed[i]);
//if(i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE - 1)) fprintf(stderr, " - ");
}
#if (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2)
/* To determine the part of the payload frame, we need to check the /* To determine the part of the payload frame, we need to check the
* Hamming code result, the CRC and the frame number */ * Hamming code result, the CRC and the frame number */
// if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 0)) || // if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 0)) ||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 1))) // (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 1)))
if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 0)) || if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 0)) ||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 1))) ((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 1)))
{ {
/* First part of the super frame */ /* First part of the super frame */
PartOfSuperFrame = 1; PartOfSuperFrame = 1;
//fprintf(stderr, "\nFirst part of the Super Frame");
/* The next part will normally be the second part */ /* The next part will normally be the second part */
opts->dPMR_next_part_of_superframe = 2; opts->dPMR_next_part_of_superframe = 2;
@@ -368,20 +296,19 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
/* BUGFIX : Copy in all case the TG ID */ /* BUGFIX : Copy in all case the TG ID */
strcpy((char *)state->dPMRVoiceFS2Frame.CalledID, (char *)CalledID); strcpy((char *)state->dPMRVoiceFS2Frame.CalledID, (char *)CalledID);
} }
/* To determine the part of the payload frame, we need to check the /* To determine the part of the payload frame, we need to check the
* Hamming code result, the CRC and the frame number */ * Hamming code result, the CRC and the frame number */
// else if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 2)) || // else if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 2)) ||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 3))) // (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 3)))
else if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 2)) || else if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 2)) ||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 3))) ((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 3)))
{ {
/* Second part of the super frame */ /* Second part of the super frame */
PartOfSuperFrame = 2; PartOfSuperFrame = 2;
//fprintf(stderr, "\nSecond part of the Super Frame");
/* The next part will normally be the first part */ /* The next part will normally be the first part */
opts->dPMR_next_part_of_superframe = 1; opts->dPMR_next_part_of_superframe = 1;
@@ -394,7 +321,9 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
CallingID[7] = '\0'; CallingID[7] = '\0';
/* Determine if the calling SRC ID is correct */ /* Determine if the calling SRC ID is correct */
//if(HammingOk[0] && CrcOk[0] && HammingOk[1] && CrcOk[1]) //if(HammingOk[0] && CrcOk[0] && HammingOk[1] && CrcOk[1])
if((CrcOk[0] || (HammingCorrectable[0][0] && HammingCorrectable[0][1])) && if((CrcOk[0] || (HammingCorrectable[0][0] && HammingCorrectable[0][1])) &&
(CrcOk[1] || (HammingCorrectable[1][0] && HammingCorrectable[1][1]))) (CrcOk[1] || (HammingCorrectable[1][0] && HammingCorrectable[1][1])))
{ {
@@ -422,132 +351,151 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
/* Set the next part of the superframe to receive */ /* Set the next part of the superframe to receive */
if(opts->dPMR_next_part_of_superframe == 1) if(opts->dPMR_next_part_of_superframe == 1)
{ {
//fprintf(stderr, "Supposed first part of the Super Frame\n");
/* Set the next part as the second part */ /* Set the next part as the second part */
opts->dPMR_next_part_of_superframe = 2; opts->dPMR_next_part_of_superframe = 2;
} }
else if(opts->dPMR_next_part_of_superframe == 2) else if(opts->dPMR_next_part_of_superframe == 2)
{ {
//fprintf(stderr, "Supposed second part of the Super Frame\n");
/* Set the next part as the first part */ /* Set the next part as the first part */
opts->dPMR_next_part_of_superframe = 1; opts->dPMR_next_part_of_superframe = 1;
} }
else else
{ {
//fprintf(stderr, "Unknown part of the Super Frame\n");
/* Unknown current part, set to 0 */ /* Unknown current part, set to 0 */
opts->dPMR_next_part_of_superframe = 0; opts->dPMR_next_part_of_superframe = 0;
} }
} }
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
{
//only print the CC and src/tg info if CRC is good
/* Display the color code */
//fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
}
else
{
/* Unknown color code, display "??" */
//fprintf(stderr, " | Color Code=?? ");
}
/* Display the destination ID (talk group - TG) */ /* Display the destination ID (talk group - TG) */
//fprintf(stderr, "| TG=%s", CalledID); fprintf (stderr, "\n");
if(state->dPMRVoiceFS2Frame.CalledIDOk) if(state->dPMRVoiceFS2Frame.CalledIDOk)
{ {
fprintf (stderr, "%s", KGRN); fprintf (stderr, "%s", KGRN);
fprintf(stderr, "\n| TG=%s", CalledID); fprintf(stderr, " TG=%s", CalledID);
fprintf (stderr, "%s", KNRM); fprintf (stderr, "%s", KNRM);
//strcpy (state->dpmr_target_id, CalledID); //HERE HERE
state->dpmr_target_id = CalledID; //check other as well before assigning
//fprintf(stderr, " (CRC OK) "); if(state->dPMRVoiceFS2Frame.CallingIDOk) sprintf (state->dpmr_target_id, "%s", CalledID);
}
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " TG=(CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
/* Display the source ID */
if(state->dPMRVoiceFS2Frame.CallingIDOk)
{
fprintf (stderr, "%s", KGRN);
fprintf(stderr, " Src=%s", CallingID);
fprintf (stderr, "%s", KNRM);
//check other as well before assigning
if(state->dPMRVoiceFS2Frame.CalledIDOk) sprintf (state->dpmr_caller_id, "%s", CallingID);
//stashed channel code in here, more likely to be correct, but no guarantee
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1)) if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
{ {
fprintf (stderr, "%s", KGRN); fprintf (stderr, "%s", KGRN);
fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]); fprintf(stderr, " Channel Code=%02d", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
fprintf (stderr, "%s", KNRM); fprintf (stderr, "%s", KNRM);
state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
//check other as well before assigning
if(state->dPMRVoiceFS2Frame.CalledIDOk) state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
} }
} }
else else
{
//fprintf(stderr, " (CRC ERR) ");
}
/* Display the source ID */
//fprintf(stderr, "| Src=%s", CallingID);
if(state->dPMRVoiceFS2Frame.CallingIDOk)
{
fprintf (stderr, "%s", KGRN);
fprintf(stderr, "| Src=%s", CallingID);
fprintf (stderr, "%s", KNRM);
//strcpy (state->dpmr_caller_id, CallingID);
state->dpmr_caller_id = CallingID;
//fprintf(stderr, " (CRC OK) \n");
}
else
{ {
fprintf (stderr, "%s", KRED); fprintf (stderr, "%s", KRED);
fprintf(stderr, " (CRC ERR) \n"); fprintf(stderr, " Src=(CRC ERR) Channel Code =(CRC ERR)");
fprintf (stderr, "%s", KNRM); fprintf (stderr, "%s", KNRM);
} }
#endif /* (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2) */ if (state->dPMRVoiceFS2Frame.Version[0] == 3)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " Scrambler");
fprintf (stderr, "%s", KNRM);
if (state->R != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Key %05lld ", state->R );
fprintf (stderr, "%s", KNRM);
}
}
//Play only voice frames by first looking to see if there is a TCH voice in CommunicationMode, //Play only voice frames by first looking to see if there is a TCH voice in CommunicationMode,
//then sending it to be processed by processMbeFrame, its much cleaner this way
short start = 0; short start = 0;
short end = 4; short end = 4;
//not really even sure why I made this loop
//I probably should actually read the manual again
for (short o = 0; o < 2; o++) for (short o = 0; o < 2; o++)
{ {
//reset scrambler key seed on frame 0
if (state->dPMRVoiceFS2Frame.FrameNumbering[o] == 0) state->payload_miN = 0;
//depending on first or second TCH, set start and end variables appropriately //depending on first or second TCH, set start and end variables appropriately
if (o == 1) if (o == 1)
{ {
start = 4; start = 4;
end = 8; end = 8;
//add extra line break on second repitition only when dumping payload to console
if (opts->payload == 1)
{
fprintf(stderr, "\n");
}
} }
//fprintf (stderr, "\nCommunication Mode: %d\n", state->dPMRVoiceFS2Frame.CommunicationMode[o]);
//fprintf (stderr, "Encryption Mode: %d\n", state->dPMRVoiceFS2Frame.Version[o]); //this is used so we can simply pass the voice here to the
//fprintf (stderr, "Superframe Number: %d", state->dPMRVoiceFS2Frame.FrameNumbering[o]); //should be 1-4, but may be same number on TCH 1 or TCH 2 //nxdn scrambler by telling mbe these are nxdn frames and to
//apply the same descramble method to them if necessary
int realsynctype = state->synctype;
// fprintf (stderr, "\nCommunication Mode: %d\n", state->dPMRVoiceFS2Frame.CommunicationMode[o]);
// fprintf (stderr, "Encryption Mode: %d\n", state->dPMRVoiceFS2Frame.Version[o]); //shows as 3 (manufacturer specific, 5.16) on the dPMR scrambler values received
// fprintf (stderr, "Superframe Number: %d", state->dPMRVoiceFS2Frame.FrameNumbering[o]);
if((state->dPMRVoiceFS2Frame.CommunicationMode[o] == 0) || if((state->dPMRVoiceFS2Frame.CommunicationMode[o] == 0) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 1) || (state->dPMRVoiceFS2Frame.CommunicationMode[o] == 1) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 5)) (state->dPMRVoiceFS2Frame.CommunicationMode[o] == 5))
{ {
//There are 4 AMBE voice samples per TCH //check to see if we are using scrambler
if (state->dPMRVoiceFS2Frame.Version[o] == 3) //!= 0
{
state->synctype = 28; //fake it as nxdn
state->nxdn_cipher_type = 0x01; //turn on nxdn scrambler cipher
state->dmr_encL = 1; //flag on enc bit here so we can mute if no key provided
}
//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++) for(i = start; i < end; i++)
{ {
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL); processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
} //End for(i = start; i < end); i++) if (opts->floating_point == 0)
} //if comms and not encrypted playSynthesizedVoiceMS(opts, state);
}//End for TCH for o loop if (opts->floating_point == 1)
playSynthesizedVoiceFM(opts, state);
}
//set the correct sync type again and flag off the cipher
state->synctype = realsynctype;
state->nxdn_cipher_type = 0;
}
}
fprintf(stderr, "\n");
if (opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
//keep code below, could be handy cheat sheet for other info //keep code below, could be handy cheat sheet for other info
#ifdef dPMR_PRINT_DEBUG_INFO #ifdef dPMR_PRINT_DEBUG_INFO

View File

@@ -21,14 +21,16 @@ pa_sample_spec ss;
pa_sample_spec tt; pa_sample_spec tt;
pa_sample_spec zz; pa_sample_spec zz;
pa_sample_spec cc; pa_sample_spec cc;
pa_sample_spec ff; //float
//pulse audio buffer attributes (input latency)
pa_buffer_attr lt;
void closePulseOutput (dsd_opts * opts) void closePulseOutput (dsd_opts * opts)
{ {
pa_simple_free (opts->pulse_digi_dev_out); pa_simple_free (opts->pulse_digi_dev_out);
if (opts->dmr_stereo == 1) if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) //EDACS analog calls and/or monitoring source analog audio
{ pa_simple_free (opts->pulse_raw_dev_out);
pa_simple_free (opts->pulse_digi_dev_outR);
}
} }
void closePulseInput (dsd_opts * opts) void closePulseInput (dsd_opts * opts)
@@ -39,33 +41,66 @@ void closePulseInput (dsd_opts * opts)
void openPulseOutput(dsd_opts * opts) void openPulseOutput(dsd_opts * opts)
{ {
char * dev = NULL;
if (opts->pa_output_idx[0] != 0)
dev = opts->pa_output_idx;
int err = 0;
ss.format = PA_SAMPLE_S16NE; ss.format = PA_SAMPLE_S16NE;
ss.channels = opts->pulse_raw_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse ss.channels = opts->pulse_raw_out_channels;
ss.rate = opts->pulse_raw_rate_out; //48000 ss.rate = opts->pulse_raw_rate_out;
tt.format = PA_SAMPLE_S16NE; tt.format = PA_SAMPLE_S16NE;
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse tt.channels = opts->pulse_digi_out_channels;
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle tt.rate = opts->pulse_digi_rate_out;
if (opts->monitor_input_audio == 1) ff.format = PA_SAMPLE_FLOAT32NE;
ff.channels = opts->pulse_digi_out_channels;
ff.rate = opts->pulse_digi_rate_out;
//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, dev, "Analog", &ss, 0, NULL, &err);
if (err != 0)
{ {
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); fprintf (stderr, "Err: %d; %s; ", err, pa_strerror(err));
#ifdef __CYGWIN__
fprintf (stderr, "Please make sure the Pulse Audio Server Backend is running first.");
#endif
exit(0);
} }
//tt pa_channel_map* fl = 0; //NULL and 0 are same in this context
pa_channel_map* left = 0; //NULL and 0 are same in this context pa_channel_map* ss = 0; //NULL and 0 are same in this context
pa_channel_map* right = 0; //NULL and 0 are same in this context
if (opts->dmr_stereo == 0) if (opts->floating_point == 0)
{ {
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, 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->dmr_stereo == 1) if (opts->floating_point == 1)
{ {
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME1", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 1", &tt, left, NULL, NULL); opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, dev, opts->output_name, &ff, fl, NULL, &err);
opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME2", PA_STREAM_PLAYBACK, NULL, "XDMA SLOT 2", &tt, right, NULL, NULL);
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);
}
} }
} }
@@ -73,12 +108,198 @@ void openPulseOutput(dsd_opts * opts)
void openPulseInput(dsd_opts * opts) void openPulseInput(dsd_opts * opts)
{ {
char * dev = NULL;
if (opts->pa_input_idx[0] != 0)
dev = opts->pa_input_idx;
int err = 0;
cc.format = PA_SAMPLE_S16NE; cc.format = PA_SAMPLE_S16NE;
cc.channels = opts->pulse_digi_in_channels; cc.channels = opts->pulse_digi_in_channels;
cc.rate = opts->pulse_digi_rate_in; //48000 cc.rate = opts->pulse_digi_rate_in; //48000
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, opts->output_name, &cc, NULL, NULL, NULL); //adjust input latency settings (defaults are all -1 to let server set these automatically, but without pavucontrol open, this is approx 2s)
//setting fragsize to 960 for 48000 input seems to do the trick to allow a much faster latency without underrun, may need adjusting if
//modifying the input rate (will only apply IF using pulse audio input, and not any other input method)
//TODO: set fragsize vs expected input rate if required in the future
//NOTE: If users report any underrun conditions, then either change 960 back to -1, or pass NULL instead of &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)
{
int fmt;
int speed = 48000;
if (opts->audio_in_type == 5) //if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0)) or 'split' == 0
{
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
{
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
opts->audio_out_fd = open (opts->audio_out_dev, O_RDWR);
if (opts->audio_out_fd == -1)
{
fprintf (stderr, "Error, couldn't open #1 %s\n", opts->audio_out_dev);
opts->audio_out = 0;
exit(1);
}
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{
fprintf (stderr, "ioctl reset error \n");
}
fmt = speed;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
fprintf (stderr, "ioctl speed error \n");
}
fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0)
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
fprintf (stderr, "ioctl stereo error \n");
}
fmt = AFMT_S16_LE;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
fprintf (stderr, "ioctl setfmt error \n");
}
opts->audio_out_type = 5; //5 for 1 channel - 48k OSS 16-bit short output (matching with input)
opts->pulse_digi_rate_out = 48000; //this is used to force to upsample and also allow source audio monitor conditional check
opts->pulse_digi_out_channels = 1; //this is used to allow source audio monitor conditional check
opts->audio_gain = 0;
}
}
if (opts->audio_in_type != 5) //split == 1
{
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
{
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
if (opts->audio_out_fd == -1)
{
fprintf (stderr, "Error, couldn't open %s\n", opts->audio_out_dev);
opts->audio_out = 0;
exit(1);
}
//Setup the device. Note that it's important to set the sample format, number of channels and sample rate exactly in this order. Some devices depend on the order.
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{
fprintf (stderr, "ioctl reset error \n");
}
fmt = AFMT_S16_LE; //Sample Format
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
fprintf (stderr, "ioctl setfmt error \n");
}
fmt = opts->pulse_digi_out_channels; //number of channels //was 2
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0)
{
fprintf (stderr, "ioctl channel error \n");
}
//if using split with OSS output, and using EDACS w/ Analog, we have to use 48k
if (opts->frame_provoice == 1)
opts->pulse_digi_rate_out = 48000;
speed = opts->pulse_digi_rate_out; //since we have split input/output, we want to mirror pulse rate out
fmt = speed; //output rate
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
fprintf (stderr, "ioctl speed error \n");
}
if (opts->pulse_digi_out_channels == 2)
fmt = 1;
else fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
fprintf (stderr, "ioctl stereo error \n");
}
//TODO: Multiple output returns based on 8k/1, 8k/2, or maybe 48k/1? (2,3,5)??
if (opts->pulse_digi_out_channels == 2)
opts->audio_out_type = 2; //2 for 2 channel 8k OSS 16-bit short output
else if (opts->frame_m17 == 1)
opts->audio_out_type = 2;
else opts->audio_out_type = 5;
//debug
fprintf (stderr, "Using OSS Output with %dk/%d channel configuration.\n", opts->pulse_digi_rate_out, opts->pulse_digi_out_channels);
}
}
} }
void void
@@ -92,11 +313,7 @@ processAudio (dsd_opts * opts, dsd_state * state)
{ {
// detect max level // detect max level
max = 0; max = 0;
//attempt to reduce crackle by overriding the max value when not using pulse input
if (opts->audio_in_type != 0)
{
max = 3000;
}
state->audio_out_temp_buf_p = state->audio_out_temp_buf; state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++) for (n = 0; n < 160; n++)
{ {
@@ -176,8 +393,7 @@ processAudio (dsd_opts * opts, dsd_state * state)
// copy audio data to output buffer and upsample if necessary // copy audio data to output buffer and upsample if necessary
state->audio_out_temp_buf_p = state->audio_out_temp_buf; state->audio_out_temp_buf_p = state->audio_out_temp_buf;
//we only want to upsample when using sample rates greater than 8k for output, //we only want to upsample when using sample rates greater than 8k for output
//hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur.
if (opts->pulse_digi_rate_out > 8000) if (opts->pulse_digi_rate_out > 8000)
{ {
for (n = 0; n < 160; n++) for (n = 0; n < 160; n++)
@@ -201,6 +417,8 @@ processAudio (dsd_opts * opts, dsd_state * state)
*state->audio_out_float_buf_p = -32768.0F; *state->audio_out_float_buf_p = -32768.0F;
} }
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p; *state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
//tap the pointer here and store the short upsample buffer samples
state->s_lu[n] = (short) *state->audio_out_float_buf_p;
state->audio_out_buf_p++; state->audio_out_buf_p++;
state->audio_out_float_buf_p++; state->audio_out_float_buf_p++;
} }
@@ -219,6 +437,10 @@ processAudio (dsd_opts * opts, dsd_state * state)
*state->audio_out_temp_buf_p = -32768.0F; *state->audio_out_temp_buf_p = -32768.0F;
} }
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p; *state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
//tap the pointer here and store the short buffer samples
state->s_l[n] = (short) *state->audio_out_temp_buf_p;
//debug
// fprintf (stderr, " %d", state->s_l[n]);
state->audio_out_buf_p++; state->audio_out_buf_p++;
state->audio_out_temp_buf_p++; state->audio_out_temp_buf_p++;
state->audio_out_idx++; state->audio_out_idx++;
@@ -238,11 +460,7 @@ processAudioR (dsd_opts * opts, dsd_state * state)
{ {
// detect max level // detect max level
max = 0; max = 0;
//attempt to reduce crackle by overriding the max value when not using pulse input
if (opts->audio_in_type != 0)
{
max = 3000;
}
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
for (n = 0; n < 160; n++) for (n = 0; n < 160; n++)
{ {
@@ -323,7 +541,6 @@ processAudioR (dsd_opts * opts, dsd_state * state)
// copy audio data to output buffer and upsample if necessary // copy audio data to output buffer and upsample if necessary
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
//we only want to upsample when using sample rates greater than 8k for output, //we only want to upsample when using sample rates greater than 8k for output,
//hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur.
if (opts->pulse_digi_rate_out > 8000) if (opts->pulse_digi_rate_out > 8000)
{ {
for (n = 0; n < 160; n++) for (n = 0; n < 160; n++)
@@ -347,6 +564,8 @@ processAudioR (dsd_opts * opts, dsd_state * state)
*state->audio_out_float_buf_pR = -32768.0F; *state->audio_out_float_buf_pR = -32768.0F;
} }
*state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR; *state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR;
//tap the pointer here and store the short upsample buffer samples
state->s_ru[n] = (short) *state->audio_out_float_buf_pR;
state->audio_out_buf_pR++; state->audio_out_buf_pR++;
state->audio_out_float_buf_pR++; state->audio_out_float_buf_pR++;
} }
@@ -365,6 +584,8 @@ processAudioR (dsd_opts * opts, dsd_state * state)
*state->audio_out_temp_buf_pR = -32768.0F; *state->audio_out_temp_buf_pR = -32768.0F;
} }
*state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR; *state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR;
//tap the pointer here and store the short buffer samples
state->s_r[n] = (short) *state->audio_out_temp_buf_pR;
state->audio_out_buf_pR++; state->audio_out_buf_pR++;
state->audio_out_temp_buf_pR++; state->audio_out_temp_buf_pR++;
state->audio_out_idxR++; state->audio_out_idxR++;
@@ -431,10 +652,9 @@ void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample) void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
{ {
int n; UNUSED(state);
short aout_buf[160];
short *aout_buf_p;
//short aout_buf[160];
//sf_write_short(opts->wav_out_raw, aout_buf, 160); //sf_write_short(opts->wav_out_raw, aout_buf, 160);
//only write if actual audio, truncate silence //only write if actual audio, truncate silence
@@ -449,24 +669,46 @@ void
playSynthesizedVoice (dsd_opts * opts, dsd_state * state) playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{ {
ssize_t result; ssize_t result;
UNUSED(result);
//don't synthesize voice if slot is turned off
if (opts->slot1_on == 0)
{
//clear any previously buffered audio
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_buf_p = state->audio_out_buf + 100;
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_idx2 = 0;
state->audio_out_idx = 0;
goto end_psv;
}
if (state->audio_out_idx > opts->delay) if (state->audio_out_idx > opts->delay)
{ {
// output synthesized speech to sound card if (opts->audio_out_type == 5 || opts->audio_out_type == 1) //OSS
if(opts->audio_out_type == 2)
{
//go F yourself PA
}
else
{ {
//Test just sending it straight on since I think I've figured out the STDIN and RTL for Stereo //OSS 48k/1
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
state->audio_out_idx = 0; state->audio_out_idx = 0;
} }
else if (opts->audio_out_type == 0)
{
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
state->audio_out_idx = 0;
}
else if (opts->audio_out_type == 8) //UDP Audio Out -- Forgot some things still use this for now
{
udp_socket_blaster (opts, state, (state->audio_out_idx * 2), (state->audio_out_buf_p - state->audio_out_idx));
state->audio_out_idx = 0;
}
else state->audio_out_idx = 0; //failsafe for audio_out == 0
} }
end_psv:
if (state->audio_out_idx2 >= 800000) if (state->audio_out_idx2 >= 800000)
{ {
state->audio_out_float_buf_p = state->audio_out_float_buf + 100; state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
@@ -482,19 +724,28 @@ void
playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
{ {
ssize_t result; ssize_t result;
UNUSED(result);
if (state->audio_out_idxR > opts->delay) if (state->audio_out_idxR > opts->delay)
{ {
// output synthesized speech to sound card // output synthesized speech to sound card
if(opts->audio_out_type == 2) if (opts->audio_out_type == 5) //OSS
{
//go F yourself PA
}
else
{ {
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works. //OSS 48k/1
result = write (opts->audio_out_fd, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
state->audio_out_idxR = 0; state->audio_out_idxR = 0;
} }
else if (opts->audio_out_type == 0)
{
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
state->audio_out_idxR = 0;
}
else if (opts->audio_out_type == 8) //UDP Audio Out -- Not sure how this would handle, but R never gets called anymore, so just here for symmetry
{
udp_socket_blaster (opts, state, (state->audio_out_idxR * 2), (state->audio_out_buf_pR - state->audio_out_idxR));
state->audio_out_idxR = 0;
}
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
} }
@@ -511,6 +762,8 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
void void
openAudioOutDevice (dsd_opts * opts, int speed) openAudioOutDevice (dsd_opts * opts, int speed)
{ {
UNUSED(speed);
//converted to handle any calls to use portaudio //converted to handle any calls to use portaudio
if(strncmp(opts->audio_out_dev, "pa:", 3) == 0) if(strncmp(opts->audio_out_dev, "pa:", 3) == 0)
{ {
@@ -525,7 +778,7 @@ openAudioOutDevice (dsd_opts * opts, int speed)
} }
else else
{ {
struct stat stat_buf; // struct stat stat_buf;
// if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE // if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE
// { // {
// fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev); // fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev);
@@ -545,74 +798,203 @@ openAudioOutDevice (dsd_opts * opts, int speed)
void void
openAudioInDevice (dsd_opts * opts) openAudioInDevice (dsd_opts * opts)
{ {
// get info of device/file char * extension;
if(strncmp(opts->audio_in_dev, "-", 1) == 0) const char ch = '.';
{ extension = strrchr(opts->audio_in_dev, ch); //return extension if this is a .wav or .bin file
opts->audio_in_type = 1;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=48000;
opts->pulse_digi_rate_out = 8000; //set out rate to 8000 for stdin input
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open_fd(fileno(stdin), SFM_READ, opts->audio_in_file_info, 0);
if(opts->audio_in_file == NULL) { //if no extension set, give default of .wav -- bugfix for github issue #105
fprintf (stderr,"Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL)); // if (extension == NULL) extension = ".wav";
exit(1); //had this one disabled, re-enabling it now
} // get info of device/file
} if (strncmp(opts->audio_in_dev, "-", 1) == 0)
//converted to handle any calls to use portaudio
else if(strncmp(opts->audio_in_dev, "pa:", 2) == 0)
{ {
opts->audio_in_type = 0; opts->audio_in_type = 1;
fprintf (stderr,"Error, Port Audio is not supported by FME!\n"); opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
fprintf (stderr,"Using Pulse Audio Input Stream Instead! \n"); opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
sprintf (opts->audio_in_dev, "pulse"); opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open_fd(fileno(stdin), SFM_READ, opts->audio_in_file_info, 0);
if(opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
} }
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;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
if(opts->tcp_file_in == NULL)
{
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
// else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
// {
// opts->audio_in_type = 6;
// opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
// opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
// opts->audio_in_file_info->channels=1;
// opts->audio_in_file_info->seekable=0;
// opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
// opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
// if(opts->udp_file_in == NULL)
// {
// fprintf(stderr, "Error, couldn't open UDP with libsndfile: %s\n", sf_strerror(NULL));
// exit(1);
// }
// }
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0) else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
{ {
#ifdef USE_RTLSDR
opts->audio_in_type = 3; opts->audio_in_type = 3;
#elif AERO_BUILD
opts->audio_in_type = 5;
sprintf (opts->audio_in_dev, "/dev/dsp");
#else
opts->audio_in_type = 0;
sprintf (opts->audio_in_dev, "pulse");
#endif
} }
else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0) else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0)
{ {
opts->audio_in_type = 0; opts->audio_in_type = 0;
} }
//convert from opening wav files to OP25 symbol capture files since opening wav files is busted else if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0))
{
opts->audio_in_type = 5;
}
//if no extension set, treat as named pipe or extensionless wav file -- bugfix for github issue #105
else if (extension == NULL)
{
opts->audio_in_type = 2;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate = opts->wav_sample_rate;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable = 0;
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if (opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open file/pipe with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
//test .rrc files with hardset wav file settings
else if (strncmp(extension, ".rrc", 3) == 0)
{
//debug
fprintf (stderr, "Opening M17 .rrc headless wav file\n");
opts->audio_in_type = 2;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate = 48000;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable = 0;
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if(opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open %s with libsndfile: %s\n", opts->audio_in_dev, sf_strerror(NULL));
exit(1);
}
}
//TODO: test .sym files as symbol capture .bin files
else if (strncmp(extension, ".sym", 3) == 0)
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
opts->symbolfile = fopen(opts->audio_in_dev, "r");
opts->audio_in_type = 4; //symbol capture bin files
}
else
{
opts->audio_in_type = 0;
}
}
else if (strncmp(extension, ".bin", 3) == 0)
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
opts->symbolfile = fopen(opts->audio_in_dev, "r");
opts->audio_in_type = 4; //symbol capture bin files
}
else
{
opts->audio_in_type = 0;
}
}
//open as wav file as last resort, wav files subseptible to sample rate issues if not 48000
else else
{ {
struct stat stat_buf; struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0) if (stat(opts->audio_in_dev, &stat_buf) != 0)
{ {
fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); fprintf (stderr,"Error, couldn't open wav file %s\n", opts->audio_in_dev);
exit(1); exit(1);
} }
if (S_ISREG(stat_buf.st_mode)) if (S_ISREG(stat_buf.st_mode))
{ {
// is this a regular file? then process with libsndfile. opts->audio_in_type = 2; //two now, seperating STDIN and wav files
//opts->pulse_digi_rate_out = 8000; //this for wav files input? opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
// opts->audio_in_type = 1; opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
// opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); opts->audio_in_file_info->channels=1;
// opts->audio_in_file_info->channels = 1; opts->audio_in_file_info->channels = 1;
// opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
// //
// if(opts->audio_in_file == NULL) opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
// {
// fprintf (stderr,"Error, couldn't open file %s\n", opts->audio_in_dev); if(opts->audio_in_file == NULL)
// exit(1); {
// } fprintf(stderr, "Error, couldn't open wav file %s\n", opts->audio_in_dev);
exit(1);
}
opts->symbolfile = fopen(opts->audio_in_dev, "r");
opts->audio_in_type = 4; //symbol capture bin files
} }
else //open pulse audio if no bin or wav
else //seems this condition is never met
{ {
// this is a device, use old handling, pulse audio now //opts->audio_in_type = 5; //not sure if this works or needs to openPulse here
opts->audio_in_type = 0; fprintf(stderr, "Error, couldn't open input file.\n");
exit(1);
} }
} }
if (opts->split == 1) if (opts->split == 1)
{ {
fprintf (stderr,"Audio In Device: %s\n", opts->audio_in_dev); fprintf (stderr,"Audio In Device: %s\n", opts->audio_in_dev);

1988
src/dsd_audio2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -118,6 +118,8 @@ print_datascope(dsd_opts* opts, dsd_state* state, int* sbuf2)
static void static void
use_symbol (dsd_opts* opts, dsd_state* state, int symbol) use_symbol (dsd_opts* opts, dsd_state* state, int symbol)
{ {
UNUSED(symbol);
int i; int i;
int sbuf2[128]; int sbuf2[128];
int lmin, lmax, lsum; int lmin, lmax, lsum;
@@ -217,16 +219,16 @@ invert_dibit(int dibit)
return -1; return -1;
} }
static int digitize (dsd_opts* opts, dsd_state* state, int symbol) int digitize (dsd_opts* opts, dsd_state* state, int symbol)
//int digitize (dsd_opts* opts, dsd_state* state, int symbol)
{ {
// determine dibit state // determine dibit state
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18)) if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37))
{ {
// 6 +D-STAR // 6 +D-STAR
// 14 +ProVoice // 14 +ProVoice
// 18 +D-STAR_HD // 18 +D-STAR_HD
// 37 +EDACS
if (symbol > state->center) if (symbol > state->center)
{ {
@@ -241,11 +243,12 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
return (1); // +3 return (1); // +3
} }
} }
else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19)) else if ((state->synctype == 7) || (state->synctype == 15)|| (state->synctype == 19) || (state->synctype == 38))
{ {
// 7 -D-STAR // 7 -D-STAR
// 15 -ProVoice // 15 -ProVoice
// 19 -D-STAR_HD // 19 -D-STAR_HD
// 38 -EDACS
if (symbol > state->center) if (symbol > state->center)
{ {
@@ -263,27 +266,39 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) || (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
(state->synctype == 17) || (state->synctype == 36) ) (state->synctype == 17) || (state->synctype == 29) || (state->synctype == 31) ||
(state->synctype == 77) || (state->synctype == 87) ||(state->synctype == 36) ||
(state->synctype == 99) )
{ {
// 1 -P25p1 // 1 -P25p1
// 3 -X2-TDMA (inverted signal voice frame) // 3 -X2-TDMA (inverted signal voice frame)
// 5 -X2-TDMA (inverted signal data frame) // 5 -X2-TDMA (inverted signal data frame)
// 9 -NXDN (inverted voice frame) // 9 -M17 LSR
// 11 -DMR (inverted signal voice frame) // 11 -DMR (inverted signal voice frame)
// 13 -DMR (inverted signal data frame) // 13 -DMR (inverted signal data frame)
// 17 -NXDN (inverted data frame) // 17 -M17 STR
// 29 -NXDN (inverted FSW)
// 31 -YSF
// 36 -P25p2
// 77 -M17 BRT
// 87 -M17 PKT
// 99 -M17 Preamble
int valid; int valid;
int dibit; int dibit;
valid = 0; valid = 0;
if (state->synctype == 1) UNUSED(opts);
{
// Use the P25 heuristics if available //testing again, either on Voice channels only (when tuned) or with trunk disabled
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit); // if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
} if (state->synctype == 1 && opts->use_heuristics == 1)
{
// Use the P25p1 heuristics if available
valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
}
if (valid == 0) if (valid == 0)
{ {
@@ -330,21 +345,29 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
// 0 +P25p1 // 0 +P25p1
// 2 +X2-TDMA (non inverted signal data frame) // 2 +X2-TDMA (non inverted signal data frame)
// 4 +X2-TDMA (non inverted signal voice frame) // 4 +X2-TDMA (non inverted signal voice frame)
// 8 +NXDN (non inverted voice frame) // 8 +M17 LSF
// 10 +DMR (non inverted signal data frame) // 10 +DMR (non inverted signal data frame)
// 12 +DMR (non inverted signal voice frame) // 12 +DMR (non inverted signal voice frame)
// 16 +NXDN (non inverted data frame) // 16 +M17 STR
// 28 +NXND (FSW)
// 30 +YSF
// 35 +p25p2
// 76 +M17 BRT
// 86 +M17 PKT
// 98 +M17 Preamble
int valid; int valid;
int dibit; int dibit;
valid = 0; valid = 0;
if (state->synctype == 0) //testing again, either on Voice channels only (when tuned) or with trunk disabled
{ // if (state->synctype == 0 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && opts->use_heuristics == 1)
// Use the P25 heuristics if available if (state->synctype == 0 && opts->use_heuristics == 1)
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit); {
} // Use the P25p1 heuristics if available
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
}
if (valid == 0) if (valid == 0)
{ {
@@ -437,7 +460,7 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s
} }
//symbol/dibit file capture/writing //symbol/dibit file capture/writing
if (opts->symbol_out == 1) if (opts->symbol_out_f)
{ {
//fprintf (stderr, "%d", dibit); //fprintf (stderr, "%d", dibit);
fputc (dibit, opts->symbol_out_f); fputc (dibit, opts->symbol_out_f);
@@ -474,6 +497,7 @@ skipDibit (dsd_opts * opts, dsd_state * state, int count)
short sample; short sample;
int i; int i;
UNUSED(sample);
for (i = 0; i < (count); i++) for (i = 0; i < (count); i++)
{ {

View File

@@ -17,36 +17,7 @@
#include "dsd.h" #include "dsd.h"
time_t nowF; void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
char * getTimeF(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 * getDateF(void) {
char datename[120]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
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; int i, j, k;
unsigned char b; unsigned char b;
@@ -56,36 +27,22 @@ saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
fputc (err, opts->mbe_out_f); fputc (err, opts->mbe_out_f);
k = 0; k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this
{
//fprintf(stderr, "\n IMBE ");
}
for (i = 0; i < 11; i++) for (i = 0; i < 11; i++)
{ {
b = 0; b = 0;
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
b = b << 1; b = b << 1;
b = b + imbe_d[k]; b = b + imbe_d[k];
k++; k++;
} }
if (opts->payload == 1) //make opt variable later on to toggle this fputc (b, opts->mbe_out_f);
{ }
//fprintf (stderr, "%02X", b);
}
fputc (b, opts->mbe_out_f);
}
if (opts->payload == 1)
{
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
fflush (opts->mbe_out_f); fflush (opts->mbe_out_f);
} }
void void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{ {
int i, j, k; int i, j, k;
unsigned char b; unsigned char b;
@@ -95,122 +52,86 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
fputc (err, opts->mbe_out_f); fputc (err, opts->mbe_out_f);
k = 0; k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this for (i = 0; i < 6; i++)
{
//fprintf(stderr, "\n AMBE ");
}
//for (i = 0; i < 6; i++)
for (i = 0; i < 6; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
{
//fprintf (stderr, "%02X", b);
}
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80?
{
//fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit?
}
fputc (b, opts->mbe_out_f);
}
if (opts->payload == 1)
{
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
b = ambe_d[48];
fputc (b, opts->mbe_out_f);
fflush (opts->mbe_out_f);
}
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;
err = (unsigned char) state->errs2;
k = 0;
if (opts->payload == 1) //print IMBE info
{
fprintf(stderr, "\n IMBE ");
}
for (i = 0; i < 11; i++)
{ {
b = 0; b = 0;
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
b = b << 1; b = b << 1;
b = b + imbe_d[k]; b = b + ambe_d[k];
k++; k++;
} }
if (opts->payload == 1) fputc (b, opts->mbe_out_f);
{
fprintf (stderr, "%02X", b);
}
} }
b = ambe_d[48];
if (opts->payload == 1) fputc (b, opts->mbe_out_f);
{ fflush (opts->mbe_out_f);
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
//fprintf (stderr, "\n");
} }
void void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d)
PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stereo, may use this for NXDN too
{ {
int i, j, k; int i, j, k;
unsigned char b; unsigned char b;
unsigned char err; unsigned char err;
err = (unsigned char) state->errs2; err = (unsigned char) state->errs2R;
k = 0; fputc (err, opts->mbe_out_fR);
if (opts->dmr_stereo == 0)
{
fprintf (stderr, "\n");
}
if (opts->payload == 1) //print AMBE info from DMR Stereo method
{
fprintf(stderr, " AMBE ");
}
for (i = 0; i < 7; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more k = 0;
{ for (i = 0; i < 6; i++)
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
{
fprintf (stderr, "%02X", b);
}
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit, value will be either 0x00 or 0x80?
{
fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit
}
}
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) //need to fix the printouts again
{ {
fprintf (stderr, "\n"); b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
fputc (b, opts->mbe_out_fR);
} }
b = ambe_d[48];
fputc (b, opts->mbe_out_fR);
fflush (opts->mbe_out_fR);
}
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
{
fprintf(stderr, "\n IMBE ");
uint8_t imbe[88];
for (int i = 0; i < 11; i++)
{
imbe[i] = convert_bits_into_output((uint8_t *)imbe_d+(i*8), 8);
fprintf(stderr, "%02X", imbe[i]);
}
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
UNUSED(opts);
}
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
//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");
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");
} }
@@ -226,7 +147,7 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
k = 0; k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this if (opts->payload == 1)
{ {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@@ -248,12 +169,12 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
b = b & 255; b = b & 255;
k++; k++;
} }
//new printout on reading MBE files back in
if (opts->payload == 1) //make opt variable later on to toggle this if (opts->payload == 1)
{ {
fprintf (stderr, "%02X", x); fprintf (stderr, "%02X", x);
} }
//
} }
if (opts->payload == 1) if (opts->payload == 1)
{ {
@@ -273,11 +194,11 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
state->errs = state->errs2; state->errs = state->errs2;
k = 0; k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this if (opts->payload == 1)
{ {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
//for (i = 0; i < 6; i++)
for (i = 0; i < 6; i++) //breaks backwards compatablilty with 6 files for (i = 0; i < 6; i++) //breaks backwards compatablilty with 6 files
{ {
b = fgetc (opts->mbe_in_f); b = fgetc (opts->mbe_in_f);
@@ -296,13 +217,13 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
b = b & 255; b = b & 255;
k++; k++;
} }
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this if (opts->payload == 1 && i < 6)
{ {
fprintf (stderr, "%02X", x); fprintf (stderr, "%02X", x);
} }
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80? if (opts->payload == 1 && i == 6)
{ {
fprintf (stderr, "%02X", x & 0x80); //7th octet should only contain 1 bit? fprintf (stderr, "%02X", x & 0x80);
} }
} }
if (opts->payload == 1) if (opts->payload == 1)
@@ -333,14 +254,21 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
cookie[2] = fgetc (opts->mbe_in_f); cookie[2] = fgetc (opts->mbe_in_f);
cookie[3] = fgetc (opts->mbe_in_f); cookie[3] = fgetc (opts->mbe_in_f);
cookie[4] = 0; cookie[4] = 0;
//ambe+2
if (strstr (cookie, ".amb") != NULL) if (strstr (cookie, ".amb") != NULL)
{ {
state->mbe_file_type = 1; state->mbe_file_type = 1;
} }
//p1 and pv
else if (strstr (cookie, ".imb") != NULL) else if (strstr (cookie, ".imb") != NULL)
{ {
state->mbe_file_type = 0; state->mbe_file_type = 0;
} }
//d-star ambe
else if (strstr (cookie, ".dmb") != NULL)
{
state->mbe_file_type = 2;
}
else else
{ {
state->mbe_file_type = -1; state->mbe_file_type = -1;
@@ -349,85 +277,11 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
} }
//temporarily disabled until the compiler warnings can be fixed, use symbol capture or per call instead! //slot 1
//probably the easiest thing is to just have this run fclose, and have name assignment on open instead.
// void
// closeMbeOutFile (dsd_opts * opts, dsd_state * state)
// {
//
// char shell[255], newfilename[64], ext[5], datestr[32], new_path[1024];
// char tgid[17];
// int sum, i, j;
// int talkgroup;
// struct tm timep;
// int result;
//
// if (opts->mbe_out_f != NULL)
// {
// if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
// {
// sprintf (ext, ".imb");
// //strptime (opts->mbe_out_file, "%s.imb", &timep);
// }
// else
// {
// sprintf (ext, ".amb");
// //strptime (opts->mbe_out_file, "%s.amb", &timep);
// }
//
// if (state->tgcount > 0)
// {
// for (i = 0; i < 16; i++)
// {
// sum = 0;
// for (j = 0; j < state->tgcount; j++)
// {
// sum = sum + state->tg[j][i] - 48;
// }
// tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5);
// }
// tgid[16] = 0;
// talkgroup = (int) strtol (tgid, NULL, 2);
// }
// else
// {
// talkgroup = 0;
// }
//
// fflush (opts->mbe_out_f);
// fclose (opts->mbe_out_f);
// opts->mbe_out_f = NULL;
// strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep);
//
// sprintf (newfilename, "%s%s", datestr, ext); //this one
//
// if (state->lastsynctype == 0 || state->lastsynctype == 1)
// {
// sprintf (newfilename, "%s-nac%X-tg%i%s", datestr, state->nac, talkgroup, ext);
// }
//
// //sprintf (new_path, "%s%s", opts->mbe_out_dir, newfilename);
// #ifdef _WIN32
// //sprintf (shell, "move %s %s", opts->mbe_out_path, new_path);
// #else
// //sprintf (shell, "mv %s %s", opts->mbe_out_path, new_path);
// #endif
// //result = system (shell);
//
// state->tgcount = 0;
// for (i = 0; i < 25; i++)
// {
// for (j = 0; j < 16; j++)
// {
// state->tg[i][j] = 48;
// }
// }
// }
// }
//much simpler version
void closeMbeOutFile (dsd_opts * opts, dsd_state * state) void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
if (opts->mbe_out == 1) if (opts->mbe_out == 1)
{ {
if (opts->mbe_out_f != NULL) if (opts->mbe_out_f != NULL)
@@ -436,53 +290,74 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
fclose (opts->mbe_out_f); fclose (opts->mbe_out_f);
opts->mbe_out_f = NULL; opts->mbe_out_f = NULL;
opts->mbe_out = 0; opts->mbe_out = 0;
fprintf (stderr, "\nClosing MBE out file."); fprintf (stderr, "\nClosing MBE out file 1.\n");
} }
} }
} }
void //slot 2
openMbeOutFile (dsd_opts * opts, dsd_state * state) void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
{
UNUSED(state);
if (opts->mbe_outR == 1)
{
if (opts->mbe_out_fR != NULL)
{
fflush (opts->mbe_out_fR);
fclose (opts->mbe_out_fR);
opts->mbe_out_fR = NULL;
opts->mbe_outR = 0;
fprintf (stderr, "\nClosing MBE out file 2.\n");
}
}
}
void openMbeOutFile (dsd_opts * opts, dsd_state * state)
{ {
//struct timeval tv;
int i, j; int i, j;
char ext[5]; char ext[5];
char * timestr; //add timestr here, so we can assign it and also free it to prevent memory leak
char * datestr;
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15)) timestr = getTime();
{ datestr = getDate();
sprintf (ext, ".imb");
}
else
{
sprintf (ext, ".amb");
}
// reset talkgroup id buffer //phase 1 and provoice
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
{
sprintf (ext, ".imb");
}
//d-star
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
{
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
}
//dmr, nxdn, phase 2, x2-tdma
else sprintf (ext, ".amb");
//reset talkgroup id buffer
for (i = 0; i < 12; i++) for (i = 0; i < 12; i++)
{
for (j = 0; j < 25; j++)
{ {
for (j = 0; j < 25; j++) state->tg[j][i] = 0;
{
state->tg[j][i] = 0;
}
} }
}
state->tgcount = 0; state->tgcount = 0;
//gettimeofday (&tv, NULL); sprintf (opts->mbe_out_file, "%s %s S1%s", datestr, timestr, ext);
//rewrite below line to take getTime function instead?
// sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext);
sprintf (opts->mbe_out_file, "%s %s%s", getDateF(), getTimeF(), ext);
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file); sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
opts->mbe_out_f = fopen (opts->mbe_out_path, "w"); opts->mbe_out_f = fopen (opts->mbe_out_path, "w");
if (opts->mbe_out_f == NULL) if (opts->mbe_out_f == NULL)
{ {
fprintf (stderr,"Error, couldn't open %s\n", opts->mbe_out_path); fprintf (stderr,"\nError, couldn't open %s for slot 1\n", opts->mbe_out_path);
} }
else opts->mbe_out = 1; else opts->mbe_out = 1;
@@ -490,17 +365,88 @@ openMbeOutFile (dsd_opts * opts, dsd_state * state)
fprintf (opts->mbe_out_f, "%s", ext); fprintf (opts->mbe_out_f, "%s", ext);
fflush (opts->mbe_out_f); fflush (opts->mbe_out_f);
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
} }
void void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
openWavOutFile (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) )
{
sprintf (ext, ".imb");
}
//d-star
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
{
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
}
//dmr, nxdn, phase 2, x2-tdma
else sprintf (ext, ".amb");
//reset talkgroup id buffer
for (i = 0; i < 12; i++)
{
for (j = 0; j < 25; j++)
{
state->tg[j][i] = 0;
}
}
state->tgcount = 0;
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);
opts->mbe_out_fR = fopen (opts->mbe_out_path, "w");
if (opts->mbe_out_fR == NULL)
{
fprintf (stderr,"\nError, couldn't open %s for slot 2\n", opts->mbe_out_path);
}
else opts->mbe_outR = 1;
//
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)
{
UNUSED(state);
SF_INFO info; SF_INFO info;
info.samplerate = 8000; //8000 info.samplerate = 8000; //8000
info.channels = 1; info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
if (opts->wav_out_f == NULL) if (opts->wav_out_f == NULL)
@@ -508,18 +454,16 @@ openWavOutFile (dsd_opts * opts, dsd_state * state)
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file); fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
return; return;
} }
// state->wav_out_bytes = 0;
} }
void openWavOutFileL (dsd_opts * opts, dsd_state * state) void openWavOutFileL (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
SF_INFO info; SF_INFO info;
info.samplerate = 8000; //8000 info.samplerate = 8000;
info.channels = 1; info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
if (opts->wav_out_f == NULL) if (opts->wav_out_f == NULL)
@@ -527,19 +471,16 @@ void openWavOutFileL (dsd_opts * opts, dsd_state * state)
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file); fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
return; return;
} }
// state->wav_out_bytes = 0;
} }
void openWavOutFileR (dsd_opts * opts, dsd_state * state) void openWavOutFileR (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
SF_INFO info; SF_INFO info;
info.samplerate = 8000; //8000 info.samplerate = 8000; //8000
info.channels = 1; info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
opts->wav_out_fR = sf_open (opts->wav_out_fileR, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file opts->wav_out_fR = sf_open (opts->wav_out_fileR, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
if (opts->wav_out_f == NULL) if (opts->wav_out_f == NULL)
@@ -547,78 +488,148 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state)
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_fileR); fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_fileR);
return; return;
} }
// state->wav_out_bytes = 0;
} }
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state) void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
SF_INFO info; SF_INFO info;
info.samplerate = 48000; //8000 info.samplerate = 48000; //8000
info.channels = 1; info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_WRITE, &info);
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info);
if (opts->wav_out_raw == NULL) if (opts->wav_out_raw == NULL)
{ {
fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw); fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw);
return; return;
} }
// state->wav_out_bytes = 0;
} }
void closeWavOutFile (dsd_opts * opts, dsd_state * state) void closeWavOutFile (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
sf_close(opts->wav_out_f); sf_close(opts->wav_out_f);
} }
void closeWavOutFileL (dsd_opts * opts, dsd_state * state) void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
sf_close(opts->wav_out_f); sf_close(opts->wav_out_f);
} }
void closeWavOutFileR (dsd_opts * opts, dsd_state * state) void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
sf_close(opts->wav_out_fR); sf_close(opts->wav_out_fR);
} }
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state) void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
sf_close(opts->wav_out_raw); sf_close(opts->wav_out_raw);
} }
void openSymbolOutFile (dsd_opts * opts, dsd_state * state) void openSymbolOutFile (dsd_opts * opts, dsd_state * state)
{ {
//Do something closeSymbolOutFile(opts, state);
opts->symbol_out_f = fopen (opts->symbol_out_file, "w"); opts->symbol_out_f = fopen (opts->symbol_out_file, "w");
} }
void writeSymbolOutFile (dsd_opts * opts, dsd_state * state)
{
//Do something
}
void closeSymbolOutFile (dsd_opts * opts, dsd_state * state) void closeSymbolOutFile (dsd_opts * opts, dsd_state * state)
{ {
//Do something UNUSED(state);
if (opts->symbol_out == 1)
if (opts->symbol_out_f)
{ {
if (opts->symbol_out_file != NULL) //check first, or issuing a second fclose will crash the SOFTWARE fclose(opts->symbol_out_f);
{ opts->symbol_out_f = NULL;
fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once
//noCarrier(opts, state); //free(): double free detected in tcache 2 (this is a new one)
}
opts->symbol_out = 0; //set flag to 1
//sprintf (opts->symbol_out_file, "fme-capture.bin"); //use fme for the symbol bin ext
//openSymbolOutFile (opts, state);
} }
} }
//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,8 +1,48 @@
// DMR filter #include "dsd.h"
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
#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.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
#define NZEROS 60 #define NZEROS 60
float ngain = 7.423339364f; float ngain = 7.423339364f;
static float xv[NZEROS+1]; static float xv[NZEROS+1];
float xcoeffs[] = float xcoeffs[61] =
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f, { -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f, -0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f, +0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
@@ -21,70 +61,48 @@ float xcoeffs[] =
-0.0083649323f, -0.0083649323f,
}; };
// NXDN48 filter //reverted to original NXDN filters, do better with LICH/Data handling
//#define NXZEROS 134 // NXDN48 filter - Original Version
//float nxgain = 15.95930463f; #define NXZEROS 134
float nxgain = 15.95930463f;
#define NXZEROS 91 //Osmocom OP25
float nxgain = 1.0f; //Osmocom OP25
static float nxv[NXZEROS+1]; static float nxv[NXZEROS+1];
//OP25 Osmocom NXDN48 Coeffs seem to do well, will want to do some VS testing float nxcoeffs[135] =
float nxcoeffs[] = { +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f,
{ 0.00203767f, 0.00491622f, 0.00748189f, 0.00934561f, 0.01017049f, 0.00972167f, +0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f,
0.00790748f, 0.00480597f, 0.00067202f, -0.00407743f, -0.00890019f, -0.01318478f, -0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f,
-0.01632047f, -0.01777371f, -0.01716241f, -0.01431852f, -0.00933066f, -0.00255979f, -0.045828927f, -0.052119261f, -0.056372283f, -0.058221106f,
0.00537624f, 0.01364992f, 0.02130038f, 0.02733235f, 0.03082824f, 0.03106179f, -0.057387924f, -0.053703443f, -0.047122444f, -0.037734535f,
0.02760061f, 0.02038545f, 0.00977572f, -0.0034462f, -0.01811514f, -0.03276675f, -0.025769308f, -0.011595336f, +0.004287292f, +0.021260954f,
-0.04575844f, -0.05541762f, -0.06020353f, -0.0588669f, -0.05059129f, -0.03510097f, +0.038610717f, +0.055550276f, +0.071252765f, +0.084885375f,
-0.01272309f, 0.01560398f, 0.04837926f, 0.08364189f, 0.11912012f, 0.15241359f, +0.095646450f, +0.102803611f, +0.105731303f, +0.103946126f,
0.18119246f, 0.20339503f, 0.21740525f, 0.2221932f, 0.21740525f, 0.20339503f, +0.097138329f, +0.085197939f, +0.068234131f, +0.046586711f,
0.18119246f, 0.15241359f, 0.11912012f, 0.08364189f, 0.04837926f, 0.01560398f, +0.020828821f, -0.008239664f, -0.039608255f, -0.072081234f,
-0.01272309f, -0.03510097f, -0.05059129f, -0.0588669f, -0.06020353f, -0.05541762f, -0.104311776f, -0.134843790f, -0.162160200f, -0.184736015f,
-0.04575844f, -0.03276675f, -0.01811514f, -0.0034462f, 0.00977572f, 0.02038545f, -0.201094346f, -0.209863285f, -0.209831516f, -0.200000470f,
0.02760061f, 0.03106179f, 0.03082824f, 0.02733235f, 0.02130038f, 0.01364992f, -0.179630919f, -0.148282051f, -0.105841323f, -0.052543664f,
0.00537624f, -0.00255979f, -0.00933066f, -0.01431852f, -0.01716241f, -0.01777371f, +0.011020985f, +0.083912428f, +0.164857408f, +0.252278939f,
-0.01632047f, -0.01318478f, -0.00890019f, -0.00407743f, 0.00067202f, 0.00480597f, +0.344336996f, +0.438979335f, +0.534000832f, +0.627109358f,
0.00790748f, 0.00972167f, 0.01017049f, 0.00934561f, 0.00748189f, 0.00491622f, +0.715995947f, +0.798406824f, +0.872214756f, +0.935487176f,
0.00203767f}; +0.986548646f, +1.024035395f, +1.046939951f, +1.054644241f,
+1.046939951f, +1.024035395f, +0.986548646f, +0.935487176f,
//OLD nxCOEFFS +0.872214756f, +0.798406824f, +0.715995947f, +0.627109358f,
// { +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f, +0.534000832f, +0.438979335f, +0.344336996f, +0.252278939f,
// +0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f, +0.164857408f, +0.083912428f, +0.011020985f, -0.052543664f,
// -0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f, -0.105841323f, -0.148282051f, -0.179630919f, -0.200000470f,
// -0.045828927f, -0.052119261f, -0.056372283f, -0.058221106f, -0.209831516f, -0.209863285f, -0.201094346f, -0.184736015f,
// -0.057387924f, -0.053703443f, -0.047122444f, -0.037734535f, -0.162160200f, -0.134843790f, -0.104311776f, -0.072081234f,
// -0.025769308f, -0.011595336f, +0.004287292f, +0.021260954f, -0.039608255f, -0.008239664f, +0.020828821f, +0.046586711f,
// +0.038610717f, +0.055550276f, +0.071252765f, +0.084885375f, +0.068234131f, +0.085197939f, +0.097138329f, +0.103946126f,
// +0.095646450f, +0.102803611f, +0.105731303f, +0.103946126f, +0.105731303f, +0.102803611f, +0.095646450f, +0.084885375f,
// +0.097138329f, +0.085197939f, +0.068234131f, +0.046586711f, +0.071252765f, +0.055550276f, +0.038610717f, +0.021260954f,
// +0.020828821f, -0.008239664f, -0.039608255f, -0.072081234f, +0.004287292f, -0.011595336f, -0.025769308f, -0.037734535f,
// -0.104311776f, -0.134843790f, -0.162160200f, -0.184736015f, -0.047122444f, -0.053703443f, -0.057387924f, -0.058221106f,
// -0.201094346f, -0.209863285f, -0.209831516f, -0.200000470f, -0.056372283f, -0.052119261f, -0.045828927f, -0.037935027f,
// -0.179630919f, -0.148282051f, -0.105841323f, -0.052543664f, -0.028914291f, -0.019262057f, -0.009468531f, +0.000003302f,
// +0.011020985f, +0.083912428f, +0.164857408f, +0.252278939f, +0.008737200f, +0.016379869f, +0.022653298f, +0.027362877f,
// +0.344336996f, +0.438979335f, +0.534000832f, +0.627109358f, +0.030401148f, +0.031747267f, +0.031462429f,
// +0.715995947f, +0.798406824f, +0.872214756f, +0.935487176f, };
// +0.986548646f, +1.024035395f, +1.046939951f, +1.054644241f,
// +1.046939951f, +1.024035395f, +0.986548646f, +0.935487176f,
// +0.872214756f, +0.798406824f, +0.715995947f, +0.627109358f,
// +0.534000832f, +0.438979335f, +0.344336996f, +0.252278939f,
// +0.164857408f, +0.083912428f, +0.011020985f, -0.052543664f,
// -0.105841323f, -0.148282051f, -0.179630919f, -0.200000470f,
// -0.209831516f, -0.209863285f, -0.201094346f, -0.184736015f,
// -0.162160200f, -0.134843790f, -0.104311776f, -0.072081234f,
// -0.039608255f, -0.008239664f, +0.020828821f, +0.046586711f,
// +0.068234131f, +0.085197939f, +0.097138329f, +0.103946126f,
// +0.105731303f, +0.102803611f, +0.095646450f, +0.084885375f,
// +0.071252765f, +0.055550276f, +0.038610717f, +0.021260954f,
// +0.004287292f, -0.011595336f, -0.025769308f, -0.037734535f,
// -0.047122444f, -0.053703443f, -0.057387924f, -0.058221106f,
// -0.056372283f, -0.052119261f, -0.045828927f, -0.037935027f,
// -0.028914291f, -0.019262057f, -0.009468531f, +0.000003302f,
// +0.008737200f, +0.016379869f, +0.022653298f, +0.027362877f,
// +0.030401148f, +0.031747267f, +0.031462429f,
// };
// DMR filter F4EXB // DMR filter F4EXB
#define DMRNZEROS 60 #define DMRNZEROS 60
@@ -96,7 +114,7 @@ const float dmrgain = 6.82973073748f;
static float dxv[DMRNZEROS+1]; static float dxv[DMRNZEROS+1];
// DMR filter F4EXB - root raised cosine alpha=0.7 Ts = 6650 S/s Fc = 48kHz // DMR filter F4EXB - root raised cosine alpha=0.7 Ts = 6650 S/s Fc = 48kHz
const float dmrcoeffs[] = const float dmrcoeffs[61] =
{0.0301506278, 0.0269200615, 0.0159662432, -0.0013114705, -0.0216605133, {0.0301506278, 0.0269200615, 0.0159662432, -0.0013114705, -0.0216605133,
-0.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083, -0.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083,
0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780, 0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780,
@@ -110,6 +128,52 @@ const float dmrcoeffs[] =
0.0147202645, -0.0186176083, -0.0428325003, -0.0543747957, -0.0528141756, 0.0147202645, -0.0186176083, -0.0428325003, -0.0543747957, -0.0528141756,
-0.0404938748, -0.0216605133, -0.0013114705, 0.0159662432, 0.0269200615, 0.0301506278}; -0.0404938748, -0.0216605133, -0.0013114705, 0.0159662432, 0.0269200615, 0.0301506278};
// dPMR filter, version of F4EXB
static float dpmrxv[NXZEROS+1];
// dPMR filter, version of F4EXB
#define DPMRNZEROS 134
// dPMR filter, version of F4EXB
const float dpmrgain = 14.6083498224f;
// dPMR filter - root raised cosine alpha=0.2 Ts = 3325 S/s Fc = 48 kHz - zero at boundaries appears to be slightly better
const float dpmrcoeffs[135] =
{-0.0000983004, 0.0058388841, 0.0119748846, 0.0179185547, 0.0232592816,
0.0275919612, 0.0305433586, 0.0317982965, 0.0311240307,
0.0283911865, 0.0235897433, 0.0168387650, 0.0083888763,
-0.0013831396, -0.0119878087, -0.0228442151, -0.0333082708,
-0.0427067804, -0.0503756642, -0.0557003599, -0.0581561791,
-0.0573462646, -0.0530347941, -0.0451732069, -0.0339174991,
-0.0196350217, -0.0028997157, 0.0155246961, 0.0347134030,
0.0536202583, 0.0711271166, 0.0861006725, 0.0974542022,
0.1042112035, 0.1055676660, 0.1009496091, 0.0900625944,
0.0729301774, 0.0499186839, 0.0217462748, -0.0105250265,
-0.0455148664, -0.0815673067, -0.1168095612, -0.1492246435,
-0.1767350726, -0.1972941202, -0.2089805758, -0.2100926829,
-0.1992367833, -0.1754063031, -0.1380470370, -0.0871052089,
-0.0230554989, 0.0530929052, 0.1398131936, 0.2351006721,
0.3365341927, 0.4413570929, 0.5465745033, 0.6490630781,
0.7456885564, 0.8334261381, 0.9094784589, 0.9713859928,
1.0171250045, 1.0451886943, 1.0546479089, 1.0451886943,
1.0171250045, 0.9713859928, 0.9094784589, 0.8334261381,
0.7456885564, 0.6490630781, 0.5465745033, 0.4413570929,
0.3365341927, 0.2351006721, 0.1398131936, 0.0530929052,
-0.0230554989, -0.0871052089, -0.1380470370, -0.1754063031,
-0.1992367833, -0.2100926829, -0.2089805758, -0.1972941202,
-0.1767350726, -0.1492246435, -0.1168095612, -0.0815673067,
-0.0455148664, -0.0105250265, 0.0217462748, 0.0499186839,
0.0729301774, 0.0900625944, 0.1009496091, 0.1055676660,
0.1042112035, 0.0974542022, 0.0861006725, 0.0711271166,
0.0536202583, 0.0347134030, 0.0155246961, -0.0028997157,
-0.0196350217, -0.0339174991, -0.0451732069, -0.0530347941,
-0.0573462646, -0.0581561791, -0.0557003599, -0.0503756642,
-0.0427067804, -0.0333082708, -0.0228442151, -0.0119878087,
-0.0013831396, 0.0083888763, 0.0168387650, 0.0235897433,
0.0283911865, 0.0311240307, 0.0317982965, 0.0305433586,
0.0275919612, 0.0232592816, 0.0179185547, 0.0119748846,
0.0058388841, -0.0000983004};
short dsd_input_filter(short sample, int mode); short dsd_input_filter(short sample, int mode);
@@ -123,7 +187,18 @@ dmr_filter(short sample)
short short
nxdn_filter(short sample) nxdn_filter(short sample)
{ {
return dsd_input_filter(sample, 2); return dsd_input_filter(sample, 4);
}
short
dpmr_filter(short sample)
{
return dsd_input_filter(sample, 4);
}
short m17_filter (short sample)
{
return dsd_input_filter(sample, 5);
} }
@@ -144,7 +219,7 @@ dsd_input_filter(short sample, int mode)
case 2: case 2:
gain = nxgain; gain = nxgain;
v = nxv; v = nxv;
coeffs = nxcoeffs; coeffs = (float *)nxcoeffs;
zeros = NXZEROS; zeros = NXZEROS;
break; break;
case 3: case 3:
@@ -153,6 +228,20 @@ dsd_input_filter(short sample, int mode)
coeffs = (float *)dmrcoeffs; coeffs = (float *)dmrcoeffs;
zeros = DMRNZEROS; zeros = DMRNZEROS;
break; break;
case 4:
gain = dpmrgain;
v = dpmrxv;
coeffs = (float *)dpmrcoeffs;
zeros = DPMRNZEROS;
break;
case 5:
gain = m17gain;
v = m17xv;
coeffs = (float *)m17coeffs;
zeros = M17ZEROS;
break;
default: default:
return sample; return sample;
} }
@@ -160,11 +249,20 @@ dsd_input_filter(short sample, int mode)
for (i = 0; i < zeros; i++) for (i = 0; i < zeros; i++)
v[i] = v[i+1]; v[i] = v[i+1];
v[zeros] = sample; // unfiltered sample in v[zeros] = (float)sample; // unfiltered sample in
sum = 0.0f; sum = 0.0f;
for (i = 0; i <= zeros; i++) for (i = 0; i <= zeros; i++)
sum += (coeffs[i] * v[i]); sum += (coeffs[i] * v[i]);
return (short)(sum / gain); // filtered sample out return (short)(sum / gain); // filtered sample out
}
void init_rrc_filter_memory()
{
memset (m17xv, 0, 81*sizeof(float));
memset (xv, 0, 61*sizeof(float));
memset (dxv, 0, 61*sizeof(float));
memset (nxv, 0, 135*sizeof(float));
memset (dpmrxv, 0, 135*sizeof(float));
} }

View File

@@ -31,7 +31,8 @@ printFrameInfo (dsd_opts * opts, dsd_state * state)
level = (int) state->max / 164; level = (int) state->max / 164;
if (opts->verbose > 0) if (opts->verbose > 0)
{ {
//fprintf (stderr,"inlvl: %2i%% ", level); // fprintf (stderr,"inlvl: %2i%% ", level);
UNUSED(level);
} }
if (state->nac != 0) if (state->nac != 0)
{ {
@@ -59,8 +60,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
char duid[3]; char duid[3];
char nac[13]; char nac[13];
int level; int level;
UNUSED2(nac, level);
char status_0; char status_0;
UNUSED(status_0);
char bch_code[63]; char bch_code[63];
int index_bch_code; int index_bch_code;
unsigned char parity; unsigned char parity;
@@ -84,184 +87,133 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->minref = state->min; state->minref = state->min;
} }
if ((state->synctype == 8) || (state->synctype == 9)) //NXDN Voice //NXDN FSW
{ if ((state->synctype == 28) || (state->synctype == 29))
//state->rf_mod = 2; //wrong type of modulation HERE HERE {
state->nac = 0; //MBEout restored, is not handled internally by nxdn_frame.c
state->lastsrc = 0; nxdn_frame (opts, state);
state->lasttg = 0; return;
if (opts->errorbars == 1) }
{
if (opts->verbose > 0) //DSTAR
{
level = (int) state->max / 164;
//fprintf (stderr, "inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processNXDNVoice (opts, state);
//ProcessNXDNFrame (opts, state, 0);
return;
}
else if ((state->synctype == 16) || (state->synctype == 17)) //NXDN Data
{
//state->rf_mod = 2;
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
//fprintf (stderr, "inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " DATA ");
processNXDNData (opts, state);
//ProcessNXDNFrame (opts, state, 0);
return;
}
else if ((state->synctype == 6) || (state->synctype == 7)) else if ((state->synctype == 6) || (state->synctype == 7))
{ {
state->nac = 0; if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
state->lastsrc = 0; openMbeOutFile (opts, state);
state->lasttg = 0; sprintf (state->fsubtype, " VOICE ");
if (opts->errorbars == 1) processDSTAR (opts, state);
{ return;
if (opts->verbose > 0) }
{
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processDSTAR (opts, state);
return;
}
else if ((state->synctype == 18) || (state->synctype == 19)) else if ((state->synctype == 18) || (state->synctype == 19))
{ {
state->nac = 0; if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
state->lastsrc = 0; openMbeOutFile (opts, state);
state->lasttg = 0; sprintf (state->fsubtype, " DATA ");
if (opts->errorbars == 1) processDSTAR_HD (opts, state);
{ return;
if (opts->verbose > 0) }
{
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " DATA ");
processDSTAR_HD (opts, state);
return;
}
//Start DMR Types //Start DMR Types
else if ((state->synctype >= 10) && (state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC else if ((state->synctype >= 10 && state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC
{ {
//print manufacturer strings to branding, disabled 0x10 moto other systems can use that fid set
//0x06 is trident, but when searching, apparently, they developed con+, but was bought by moto?
if (state->dmr_mfid == 0x10) ; //sprintf (state->dmr_branding, "%s", "Motorola");
else if (state->dmr_mfid == 0x68) sprintf (state->dmr_branding, "%s", " Hytera");
else if (state->dmr_mfid == 0x58) sprintf (state->dmr_branding, "%s", " Tait");
//disabling these due to random data decodes setting an odd mfid, could be legit, but only for that one packet?
//or, its just a decode error somewhere
// else if (state->dmr_mfid == 0x20) sprintf (state->dmr_branding, "%s", "JVC Kenwood");
// else if (state->dmr_mfid == 0x04) sprintf (state->dmr_branding, "%s", "Flyde Micro");
// else if (state->dmr_mfid == 0x05) sprintf (state->dmr_branding, "%s", "PROD-EL SPA");
// else if (state->dmr_mfid == 0x06) sprintf (state->dmr_branding, "%s", "Motorola"); //trident/moto con+
// else if (state->dmr_mfid == 0x07) sprintf (state->dmr_branding, "%s", "RADIODATA");
// else if (state->dmr_mfid == 0x08) sprintf (state->dmr_branding, "%s", "Hytera");
// else if (state->dmr_mfid == 0x09) sprintf (state->dmr_branding, "%s", "ASELSAN");
// else if (state->dmr_mfid == 0x0A) sprintf (state->dmr_branding, "%s", "Kirisun");
// else if (state->dmr_mfid == 0x0B) sprintf (state->dmr_branding, "%s", "DMR Association");
// else if (state->dmr_mfid == 0x13) sprintf (state->dmr_branding, "%s", "EMC S.P.A.");
// else if (state->dmr_mfid == 0x1C) sprintf (state->dmr_branding, "%s", "EMC S.P.A.");
// else if (state->dmr_mfid == 0x33) sprintf (state->dmr_branding, "%s", "Radio Activity");
// else if (state->dmr_mfid == 0x3C) sprintf (state->dmr_branding, "%s", "Radio Activity");
// else if (state->dmr_mfid == 0x77) sprintf (state->dmr_branding, "%s", "Vertex Standard");
//disable so radio id doesn't blink in and out during ncurses and aggressive_framesync //disable so radio id doesn't blink in and out during ncurses and aggressive_framesync
state->nac = 0; state->nac = 0;
//state->lastsrc = 0;
//state->lasttg = 0;
//state->lastsrcR = 0;
//state->lasttgR = 0;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{ {
if (opts->verbose > 0) level = (int) state->max / 164;
{ //fprintf (stderr,"inlvl: %2i%% ", level);
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
} }
}
if ( (state->synctype == 11) || (state->synctype == 12) || (state->synctype == 32) ) //DMR Voice Modes if ( (state->synctype == 11) || (state->synctype == 12) || (state->synctype == 32) ) //DMR Voice Modes
{
sprintf (state->fsubtype, " VOICE ");
if (opts->dmr_stereo == 0 && state->synctype < 32)
{ {
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL) && opts->dmr_stereo == 0) sprintf (state->slot1light, " slot1 ");
{ sprintf (state->slot2light, " slot2 ");
openMbeOutFile (opts, state); //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);
sprintf (state->fsubtype, " VOICE "); if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
{
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
processDMRvoice (opts, state);
}
if (opts->dmr_stereo == 0 && state->synctype == 32)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
fprintf (stderr, "%s", KNRM);
}
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
{
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
if (state->synctype > 31 )
{
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
}
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
}
} }
if (opts->dmr_mono == 1 && state->synctype == 32)
{
//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->dmr_stereo == 1) //opts->dmr_stereo == 1
{
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
if (state->synctype > 31 )
{
//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); //bootstrap into MS Bootstrap (voice only)
}
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
}
}
else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data
{ {
if (opts->dmr_stereo == 0) if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
{ if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
closeMbeOutFile (opts, state); if (opts->p25_trunk == 0) dmrMSData (opts, state);
state->err_str[0] = 0;
fprintf (stderr, "%s", KRED);
fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
fprintf (stderr, "%s", KNRM);
}
if (opts->dmr_stereo == 1)
{
dmrMSData (opts, state);
}
} }
else else
{ {
if (opts->dmr_stereo == 0) if (opts->dmr_stereo == 0)
{ {
closeMbeOutFile (opts, state); if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
state->err_str[0] = 0; state->err_str[0] = 0;
sprintf (state->slot1light, " slot1 "); sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 "); sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync dmr_data_sync (opts, state);
processDMRdata (opts, state);
} }
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata //switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
if (opts->dmr_stereo == 1) if (opts->dmr_stereo == 1)
{ {
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
state->dmr_stereo = 0; //set the state to zero for handling pure data frames state->dmr_stereo = 0; //set the state to zero for handling pure data frames
sprintf (state->slot1light, " slot1 "); sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 "); sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync dmr_data_sync (opts, state);
processDMRdata (opts, state);
} }
} }
return; return;
} }
else if ((state->synctype >= 2) && (state->synctype <= 5)) //X2-TDMA
else if ((state->synctype >= 2) && (state->synctype <= 5))
{ {
state->nac = 0; state->nac = 0;
if (opts->errorbars == 1) if (opts->errorbars == 1)
@@ -271,15 +223,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
if ((state->synctype == 3) || (state->synctype == 4)) if ((state->synctype == 3) || (state->synctype == 4))
{ {
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{ {
openMbeOutFile (opts, state); openMbeOutFile (opts, state);
} }
sprintf (state->fsubtype, " VOICE "); sprintf (state->fsubtype, " VOICE ");
processX2TDMAvoice (opts, state); processX2TDMAvoice (opts, state);
} }
else else
{ {
closeMbeOutFile (opts, state); if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
state->err_str[0] = 0; state->err_str[0] = 0;
processX2TDMAdata (opts, state); processX2TDMAdata (opts, state);
} }
@@ -287,48 +239,57 @@ processFrame (dsd_opts * opts, dsd_state * state)
} }
else if ((state->synctype == 14) || (state->synctype == 15)) else if ((state->synctype == 14) || (state->synctype == 15))
{ {
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{ {
if (opts->verbose > 0) level = (int) state->max / 164;
{ //fprintf (stderr,"inlvl: %2i%% ", level);
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
} }
}
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{ {
openMbeOutFile (opts, state); openMbeOutFile (opts, state);
} }
sprintf (state->fsubtype, " VOICE "); sprintf (state->fsubtype, " VOICE ");
processProVoice (opts, state); processProVoice (opts, state);
return; return;
} }
//edacs
else if ((state->synctype == 37) || (state->synctype == 38))
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
edacs (opts, state);
return;
}
//ysf //ysf
else if ((state->synctype == 30) || (state->synctype == 31)) else if ((state->synctype == 30) || (state->synctype == 31))
{ {
//Do stuff //relocate MBEout to inside frame handling -- Not Working Currently for YSF
//fprintf(stderr, "YSF Sync! \n");
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
//openMbeOutFile (opts, state);
}
//sprintf(state->fsubtype, " VOICE ");
processYSF(opts, state); processYSF(opts, state);
return; 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) ||
(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;
}
//P25 P2 //P25 P2
else if ((state->synctype == 35) || (state->synctype == 36)) else if ((state->synctype == 35) || (state->synctype == 36))
{ {
//Do stuff //relocate MBEout to inside frame handling
//fprintf(stderr, "YSF Sync! \n");
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
//openMbeOutFile (opts, state);
}
//sprintf(state->fsubtype, " VOICE ");
processP2(opts, state); processP2(opts, state);
return; return;
} }
@@ -337,6 +298,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
/* dPMR Frame Sync 1 */ /* dPMR Frame Sync 1 */
fprintf(stderr, "dPMR Frame Sync 1 "); fprintf(stderr, "dPMR Frame Sync 1 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
} }
else if ((state->synctype == 21) || (state->synctype == 25)) else if ((state->synctype == 21) || (state->synctype == 25))
{ {
@@ -355,12 +317,12 @@ processFrame (dsd_opts * opts, dsd_state * state)
} }
state->nac = 0; state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{ {
openMbeOutFile (opts, state); openMbeOutFile (opts, state);
} }
sprintf(state->fsubtype, " VOICE "); sprintf(state->fsubtype, " VOICE ");
processdPMRvoice (opts, state); processdPMRvoice (opts, state);
return; return;
@@ -369,11 +331,13 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
/* dPMR Frame Sync 3 */ /* dPMR Frame Sync 3 */
fprintf(stderr, "dPMR Frame Sync 3 "); fprintf(stderr, "dPMR Frame Sync 3 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
} }
else if ((state->synctype == 23) || (state->synctype == 27)) else if ((state->synctype == 23) || (state->synctype == 27))
{ {
/* dPMR Frame Sync 4 */ /* dPMR Frame Sync 4 */
fprintf(stderr, "dPMR Frame Sync 4 "); fprintf(stderr, "dPMR Frame Sync 4 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
} }
//dPMR //dPMR
else //P25 else //P25
@@ -446,7 +410,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (new_nac != state->nac) { if (new_nac != state->nac) {
// NAC fixed by error correction // NAC fixed by error correction
state->nac = new_nac; state->nac = new_nac;
if (state->p2_hardset == 0 && new_nac != 0) //apparently, both 0 and 0xFFF can the BCH code on signal drop
if (state->p2_hardset == 0 && new_nac != 0 && new_nac != 0xFFF)
{ {
state->p2_cc = new_nac; state->p2_cc = new_nac;
} }
@@ -472,15 +437,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
// Header Data Unit // Header Data Unit
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," HDU\n"); fprintf (stderr," HDU\n");
} }
if (opts->mbe_out_dir[0] != 0) if (opts->mbe_out_dir[0] != 0)
{ {
closeMbeOutFile (opts, state); if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
openMbeOutFile (opts, state); if (opts->mbe_out_f == NULL) openMbeOutFile (opts, state);
} }
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lastp25type = 2; state->lastp25type = 2;
state->dmrburstL = 25; state->dmrburstL = 25;
@@ -492,26 +457,22 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
// Logical Link Data Unit 1 // Logical Link Data Unit 1
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," LDU1 "); fprintf (stderr," LDU1 ");
} }
if (opts->mbe_out_dir[0] != 0) if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{ {
if (opts->mbe_out_f == NULL) openMbeOutFile (opts, state);
{
openMbeOutFile (opts, state);
}
} }
}
state->lastp25type = 1; state->lastp25type = 1;
state->dmrburstL = 26; state->dmrburstL = 26;
state->currentslot = 0; state->currentslot = 0;
sprintf (state->fsubtype, " LDU1 "); sprintf (state->fsubtype, " LDU1 ");
state->numtdulc = 0; state->numtdulc = 0;
if (state->payload_algid == 0x81)
{
fprintf (stderr, "\n");
}
processLDU1 (opts, state); processLDU1 (opts, state);
} }
@@ -523,27 +484,27 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (state->lastp25type != 1) if (state->lastp25type != 1)
{ {
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n"); fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n");
} }
state->lastp25type = 0; state->lastp25type = 0;
sprintf (state->fsubtype, " "); sprintf (state->fsubtype, " ");
} }
else else
{ {
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," LDU2 "); fprintf (stderr," LDU2 ");
} }
if (opts->mbe_out_dir[0] != 0) if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{ {
if (opts->mbe_out_f == NULL) openMbeOutFile (opts, state);
{
openMbeOutFile (opts, state);
}
} }
}
state->lastp25type = 2; state->lastp25type = 2;
sprintf (state->fsubtype, " LDU2 "); sprintf (state->fsubtype, " LDU2 ");
state->numtdulc = 0; state->numtdulc = 0;
@@ -555,25 +516,25 @@ processFrame (dsd_opts * opts, dsd_state * state)
// Terminator with subsequent Link Control // Terminator with subsequent Link Control
state->dmrburstL = 28; state->dmrburstL = 28;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," TDULC\n"); fprintf (stderr," TDULC\n");
} }
if (opts->mbe_out_dir[0] != 0) if (opts->mbe_out_dir[0] != 0)
{ {
closeMbeOutFile (opts, state); if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
} }
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0; // state->lasttg = 0;
state->lastsrc = 0; // state->lastsrc = 0;
state->lastp25type = 0; state->lastp25type = 0;
state->err_str[0] = 0; state->err_str[0] = 0;
sprintf (state->fsubtype, " TDULC "); sprintf (state->fsubtype, " TDULC ");
state->numtdulc++; state->numtdulc++;
if ((opts->resume > 0) && (state->numtdulc > opts->resume)) if ((opts->resume > 0) && (state->numtdulc > opts->resume))
{ {
resumeScan (opts, state); resumeScan (opts, state);
} }
processTDULC (opts, state); processTDULC (opts, state);
state->err_str[0] = 0; state->err_str[0] = 0;
} }
@@ -582,14 +543,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
// Terminator without subsequent Link Control // Terminator without subsequent Link Control
state->dmrburstL = 28; state->dmrburstL = 28;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," TDU\n"); fprintf (stderr," TDU\n");
} }
if (opts->mbe_out_dir[0] != 0) if (opts->mbe_out_dir[0] != 0)
{ {
closeMbeOutFile (opts, state); if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
} }
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0; state->lasttg = 0;
state->lastsrc = 0; state->lastsrc = 0;
@@ -603,120 +564,59 @@ processFrame (dsd_opts * opts, dsd_state * state)
{ {
state->dmrburstL = 29; state->dmrburstL = 29;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," TSBK"); fprintf (stderr," TSBK");
} }
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
if (opts->resume > 0) if (opts->resume > 0)
{ {
resumeScan (opts, state); resumeScan (opts, state);
} }
state->lasttg = 0; state->lasttg = 0;
state->lastsrc = 0; state->lastsrc = 0;
state->lastp25type = 3; state->lastp25type = 3;
sprintf (state->fsubtype, " TSBK "); sprintf (state->fsubtype, " TSBK ");
// Now processing NID
processTSBK(opts, state); processTSBK(opts, state);
} }
else if (strcmp (duid, "30") == 0) else if (strcmp (duid, "30") == 0)
{ {
state->dmrburstL = 29;
if (opts->errorbars == 1) if (opts->errorbars == 1)
{ {
printFrameInfo (opts, state); printFrameInfo (opts, state);
fprintf (stderr," PDU\n"); fprintf (stderr," MPDU\n"); //multi block format PDU
} }
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
if (opts->resume > 0) if (opts->resume > 0)
{ {
resumeScan (opts, state); resumeScan (opts, state);
} }
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
state->lastp25type = 4; state->lastp25type = 4;
sprintf (state->fsubtype, " PDU "); sprintf (state->fsubtype, " MPDU ");
}
// try to guess based on previous frame if unknown type
else if (state->lastp25type == 1)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr,"(LDU2) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU2
state->lastp25type = 2;
sprintf (state->fsubtype, "(LDU2) ");
state->numtdulc = 0;
processLDU2 (opts, state);
}
else if (state->lastp25type == 2)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr,"(LDU1) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU1
state->lastp25type = 1;
sprintf (state->fsubtype, "(LDU1) ");
state->numtdulc = 0;
processLDU1 (opts, state);
}
else if (state->lastp25type == 3)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," (TSBK)\n");
}
//state->lastp25type = 0;
// Guess that the state is TSBK
state->lastp25type = 3;
sprintf (state->fsubtype, "(TSBK) ");
// Now processing NID processMPDU(opts, state);
skipDibit (opts, state, 328-25);
}
else if (state->lastp25type == 4)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," (PDU)\n");
}
state->lastp25type = 0;
} }
else else
{
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
if (opts->errorbars == 1)
{ {
state->lastp25type = 0; printFrameInfo (opts, state);
sprintf (state->fsubtype, " "); // fprintf (stderr," duid:%s *Unknown DUID*\n", duid);
if (opts->errorbars == 1) fprintf (stderr," duid:%s \n", duid); //DUID ERR
{
printFrameInfo (opts, state);
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
// fprintf (stderr, "\n"); //prints on dPMR frame 3
}
} }
}
} }

File diff suppressed because it is too large Load Diff

766
src/dsd_gps.c Normal file
View File

@@ -0,0 +1,766 @@
/*-------------------------------------------------------------------------------
* dsd_gps.c
* GPS Handling Functions for Various Protocols
*
* LWVMOBILE
* 2023-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
void lip_protocol_decoder (dsd_opts * opts, dsd_state * state, uint8_t * input)
{
//NOTE: This is defined in ETSI TS 102 361-4 V1.12.1 (2023-07) p208
//6.6.11.3.2 USBD Polling Service Poll Response PDU for LIP (That's a mouthful)
int slot = state->currentslot;
//NOTE: This format is pretty much the same as DMR EMB GPS, but has a few extra elements,
//so I got lazy and just lifted most of the code from there, also assuming same lat/lon calcs
//since those have been tested to work in DMR EMB GPS and units are same in LIP
fprintf (stderr, "Location Information Protocol; ");
// uint8_t service_type = (uint8_t)ConvertBitIntoBytes(&input[0], 4); //checked before arrival here
uint8_t time_elapsed = (uint8_t)ConvertBitIntoBytes(&input[6], 2);
uint8_t lon_sign = input[8];
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&input[9], 24); //8, 25
uint8_t lat_sign = input[33];
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&input[34], 23); //33, 24
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&input[57], 2);
uint8_t hor_vel = (uint8_t)ConvertBitIntoBytes(&input[59], 7);
uint8_t dir_tra = (uint8_t)ConvertBitIntoBytes(&input[66], 4);
uint8_t reason = (uint8_t)ConvertBitIntoBytes(&input[70], 3);
uint8_t add_hash = (uint8_t)ConvertBitIntoBytes(&input[73], 8); //MS Source Address Hash
//NOTE: May need to use double instead of float to avoid rounding errors
double latitude, longitude = 0.0f;
double lat_unit = (double)180/ pow (2.0, 24); //180 divided by 2^24 -- 6.3.30
double lon_unit = (double)360/ pow (2.0, 25); //360 divided by 2^25 -- 6.3.50
double lon_sf = 1.0f; //float value we can multiple longitude with
double lat_sf = 1.0f; //float value we can multiple latitude with
char latstr[3];
char lonstr[3];
sprintf (latstr, "%s", "N");
sprintf (lonstr, "%s", "E");
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
//lat and lon calculations
if (lat_sign)
{
lat = 0x800001 - lat;
sprintf (latstr, "%s", "S");
lat_sf = -1.0f;
}
latitude = ((double)lat * lat_unit);
if (lon_sign)
{
lon = 0x1000001 - lon;
sprintf (lonstr, "%s", "W");
lon_sf = -1.0f;
}
longitude = ((double)lon * lon_unit);
//6.3.63 Position Error
//6.3.17 Horizontal velocity
/*
Horizontal velocity shall be encoded for speeds 0 km/h to 28 km/h in 1 km/h steps and
from 28 km/h onwards using equation: v = C × (1 + x)^(K-A) + B where:
*/
float v = 0.0f;
float C = 16.0f;
float x = 0.038f;
float A = 13.0f;
float K = (float)hor_vel;
float B = 0.0f;
if (hor_vel > 28)
v = C * (pow(1+x, K-A)) + B; //I think this pow function is set up correctly
else v = (float)hor_vel;
float dir = (((float)dir_tra + 11.25f)/22.5f); //page 68, Table 6.45
//truncated and rounded forms
int vt = (int)v;
int dt = (int)dir;
//sanity check
if (abs (latitude) < 90 && abs(longitude) < 180)
{
fprintf (stderr, "Src(Hash); %03d; Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf); Spd: %d km/h; Dir: %d%s",add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude, vt, dt, deg_glyph);
//6.3.63 Position Error
uint16_t position_error = 2 * pow(10, pos_err); //2 * 10^pos_err
if (pos_err == 0x7 ) fprintf (stderr, "\n Position Error: Unknown or Invalid;");
else fprintf (stderr, "\n Position Error: Less than %dm;", position_error);
//Reason For Sending 6.6.11.3.3 Table 6.80
if (reason) fprintf (stderr, " Reserved: %d;", reason);
else fprintf (stderr, " Request Response; ");
//6.3.78 Time elapsed
if (time_elapsed == 0) fprintf (stderr, " TE: < 5s;");
if (time_elapsed == 1) fprintf (stderr, " TE: < 5m;");
if (time_elapsed == 2) fprintf (stderr, " TE: < 30m;");
if (time_elapsed == 3) fprintf (stderr, " TE: NA or UNK;"); //not applicable or unknown
//save to array for ncurses
if (pos_err != 0x7)
{
sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s; Err: %dm; Spd: %d km/h; Dir: %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, position_error, vt, dt, deg_glyph);
}
else sprintf (state->dmr_embedded_gps[slot], "%03d; LIP: %.5lf%s%s %.5lf%s%s Unknown Pos Err; Spd: %d km/h; Dir %d%s", add_hash, latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, vt, dt, deg_glyph);
//save to LRRP report for mapping/logging
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", datestr );
fprintf (pFile, "%s\t", timestr );
fprintf (pFile, "%08d\t", add_hash);
fprintf (pFile, "%.5lf\t", latitude);
fprintf (pFile, "%.5lf\t", longitude);
fprintf (pFile, "%d\t", vt); //speed in km/h
fprintf (pFile, "%d\t", dt); //direction of travel
fprintf (pFile, "\n");
fclose (pFile);
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
}
}
else fprintf (stderr, " Position Calculation Error;");
}
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type)
{
int slot = state->currentslot;
//NOTE: The Only difference between Short (type == 1) and Long Format (type == 2)
//is the utc_ss3 on short vs utc_ss6 and inclusion of COG value on long
//NOTE: MFID Specific Formats are not handled here, unknown, could be added if worked out
//they could share most of the same elements and use the large spare bits in block 2 for extra
// uint8_t mfid = (uint8_t)ConvertBitIntoBytes(&input[88], 8); //on type 3, last octet of first block carries MFID
// uint8_t nmea_c = input[0]; //encrypted -- checked before we get here
uint8_t nmea_ns = input[1]; //north/south (lat sign)
uint8_t nmea_ew = input[2]; //east/west (lon sign)
uint8_t nmea_q = input[3]; //Quality Indicator (no fix or fix valid)
uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[4], 7); //speed in knots (127 = greater than 126 knots)
//Latitude Bits
uint8_t nmea_ndeg = (uint8_t)ConvertBitIntoBytes(&input[11], 7); //Latitude Degrees
uint8_t nmea_nmin = (uint8_t)ConvertBitIntoBytes(&input[18], 6); //Latitude Minutes
uint16_t nmea_nminf = (uint16_t)ConvertBitIntoBytes(&input[24], 14); //Latitude Fractions of Minutes
//Longitude Bits
uint8_t nmea_edeg = (uint8_t)ConvertBitIntoBytes(&input[38], 8); //Longitude Degrees
uint8_t nmea_emin = (uint8_t)ConvertBitIntoBytes(&input[46], 6); //Longitude Minutes
uint16_t nmea_eminf = (uint16_t)ConvertBitIntoBytes(&input[52], 14); //Longitude Fractions of Minutes
//UTC Time and COG
uint8_t nmea_utc_hh = (uint8_t)ConvertBitIntoBytes(&input[66], 5);
uint8_t nmea_utc_mm = (uint8_t)ConvertBitIntoBytes(&input[71], 6);
//seconds and the addition of COG is the difference between short and long formats
uint8_t nmea_utc_ss3 = (uint8_t)ConvertBitIntoBytes(&input[77], 3); //seconds in 10s
uint8_t nmea_utc_ss6 = (uint8_t)ConvertBitIntoBytes(&input[77], 6); //seconds in 1s
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[103], 9); //course over ground in degrees
//lat and lon conversion
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
float latitude = 0.0f;
float longitude = 0.0f;
// float m_unit = 1.0f / 60.0f; //unit to convert min into decimal value - (1/60)*60 minutes = 1 degree
// float mm_unit = 1.0f / 10000.0f; //unit to convert minf into decimal value - (0000 - 9999) 0.0001×9999 = .9999 minutes, so its sub 1 minute decimal
//testing w/ Harris NMEA like values (ran tests over there with this code, this seems to work on those values)
float m_unit = 1.0f / 60.0f; //unit to convert min into decimal value - (1/60)*60 minutes = 1 degree
float mm_unit = 1.0f / 600000.0f; //unit to convert minf into decimal value - (0000 - 9999) 0.0001×9999 = .9999 minutes, so its sub 1 minute decimal
//speed conversion
float fmps, fmph, fkph = 0.0f; //conversion of knots to mps, kph, and mph values
fmps = (float)nmea_speed * 0.514444; UNUSED(fmps);
fmph = (float)nmea_speed * 1.15078f; UNUSED(fmph);
fkph = (float)nmea_speed * 1.852f;
//calculate decimal representation of latidude and longitude (need some samples to test)
latitude = ( (float)nmea_ndeg + ((float)nmea_nmin*m_unit) + ((float)nmea_nminf*mm_unit) );
longitude = ( (float)nmea_edeg + ((float)nmea_emin*m_unit) + ((float)nmea_eminf*mm_unit) );
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
//Speed in Knots
if (nmea_speed > 126)
fprintf (stderr, " SPD > 126 knots or %f kph;", fkph);
else
fprintf (stderr, " SPD: %d knots; %f kph;", nmea_speed, fkph);
//Print UTC Time and COG according to Format Type
if (type == 1)
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; Short Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss3);
if (type == 2)
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; COG: %d%s; Long Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss6, nmea_cog, deg_glyph);
//save to ncurses string
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
//save to LRRP report for mapping/logging
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", 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);
fprintf (pFile, "%d\t ", s);
fprintf (pFile, "%d\t ", a);
fprintf (pFile, "\n");
fclose (pFile);
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
}
}
//restructured the Harris GPS to flow more like the DMR UDT NMEA Format when possible
void nmea_harris (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int slot)
{
//GPS working, Time Working (old method), COG and Speed are logical on due west sample
//TODO: Fiddle/Test various ns and ew bits for proper signs in case its located elsewhere
//UPDATE: Found two contiguous bits that always work on all my accumulated samples
//the bits also place it with the 'lone' flagged bit observed prior
uint8_t nmea_ns = input[88]; //north/south (lat sign) //72 previously used bit
uint8_t nmea_ew = input[89]; //east/west (lon sign) //88 previously used bit
uint8_t nmea_q = input[147]; //Quality Indicator (last fix or current fix)
// uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[129], 7); //129,7
uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[129], 6); //this is one bit shorter than called for, but I believe it works
//Latitude Bits
uint8_t nmea_ndeg = (uint8_t)ConvertBitIntoBytes(&input[65], 7); //Latitude Degrees
uint8_t nmea_nmin = (uint8_t)ConvertBitIntoBytes(&input[58], 6); //Latitude Minutes
uint16_t nmea_nminf = (uint16_t)ConvertBitIntoBytes(&input[42], 14); //Latitude Fractions of Minutes
//Longitude Bits
uint8_t nmea_edeg = (uint8_t)ConvertBitIntoBytes(&input[96], 8); //Longitude Degrees
uint8_t nmea_emin = (uint8_t)ConvertBitIntoBytes(&input[90], 6); //Longitude Minutes
uint16_t nmea_eminf = (uint16_t)ConvertBitIntoBytes(&input[74], 14); //Longitude Fractions of Minutes
//NOTE: Removed UTC hh.mm.ss6 format found in DMR UDT, could not make it work
//with bits already established for time and it works extremely well as is
//Course Over Ground in Degrees (0-360)
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[135], 9) % 360; //course over ground in degrees //working on due west sample without %360
//timestamp (16-bit value w/ appended 17th bit to MSB)
uint32_t rtime = (uint32_t)ConvertBitIntoBytes(&input[104], 16);
rtime |= input[144] << 16; //this bit is flagged on after 0xFFFF rollover in the late afternoon
uint32_t thour = rtime / 3600;
uint32_t tmin = (rtime % 3600) / 60;
uint32_t tsec = (rtime % 3600) % 60;
//lat and lon conversion
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
float latitude = 0.0f;
float longitude = 0.0f;
float m_unit = 1.0f / 60.0f;
float mm_unit = 1.0f / 600000.0f;
//speed conversion
float fmps, fmph, fkph = 0.0f; //conversion of knots to mps, kph, and mph values
fmps = (float)nmea_speed * 0.514444; UNUSED(fmps);
fmph = (float)nmea_speed * 1.15078f; UNUSED(fmph);
fkph = (float)nmea_speed * 1.852f; UNUSED(fkph);
//calculate decimal representation of latidude and longitude (need some samples to test)
latitude = ( (float)nmea_ndeg + ((float)nmea_nmin*m_unit) + ((float)nmea_nminf*mm_unit) );
longitude = ( (float)nmea_edeg + ((float)nmea_emin*m_unit) + ((float)nmea_eminf*mm_unit) );
//This is opposite (seemingly) compared to the version specified by DMR UDT NMEA, could still be different bits involved (to be tested)
// if (nmea_ns) latitude *= -1.0f; //1 is South, 0 is North
// if (nmea_ew) longitude *= -1.0f; //1 is West, 0 is East
//DMR UDT NMEA original version (working now with new bit selection 88 and 89 like how DMR UDT NMEA format specifies)
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
if (!nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
fprintf (stderr, "\n");
fprintf (stderr, " VCH: %d - SRC: %08d;", slot, src);
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
//Speed in Knots (assuming in knots, and not in mps, or kph)
if (nmea_speed > 126)
fprintf (stderr, " SPD > 126 knots or %f MPH;", fmph); //using MPH here, its Harris, they're in the U.S.
else
fprintf (stderr, " SPD: %d knots; %f MPH;", nmea_speed, fmph);
//Course Over Ground (COG)
fprintf (stderr, " COG: %03d%s;", nmea_cog, deg_glyph); //%360
//debug speed
// fprintf (stderr, " RSPD: %02X;", nmea_speed);
//debug cog
// fprintf (stderr, " RCOG: %03X;", nmea_cog >> 0);
//UTC Time
fprintf (stderr, " T: %02d:%02d:%02d UTC;", thour, tmin, tsec);
//Fix Indicator
if (nmea_q) fprintf (stderr, " Current Fix;");
else fprintf (stderr, " Last Fix;");
//save to ncurses string
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
//save to LRRP report for mapping/logging
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", 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);
fprintf (pFile, "%d\t ", s);
fprintf (pFile, "%d\t ", a);
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
//not including the CRC obviously, unsure of their meaning, could relate
//to other GPS functions like precision, etc, unknown.
//NOTE2: All these values are just best effort based on observation and
//making map points match using logic and distance over time for speed and course
//without any documentation, any of these values may still be wrong
}
//fallback version (if desired/required)
void harris_gps(dsd_opts * opts, dsd_state * state, int slot, uint8_t * input)
{
uint8_t lat_sign, lat_deg, lat_min = 0;
uint8_t lon_sign, lon_deg, lon_min = 0;
uint16_t lat_mmin = 0;
uint16_t lon_mmin = 0;
//potentially in this PDU, but unverifiable without documentation or reasonable
//mathematical proof vs map points and direction of travel / distance over time (assuming the radio is facing that direction)
uint16_t rspeed = (uint16_t)ConvertBitIntoBytes(&input[136], 8); //MSB //136
rspeed = (rspeed << 8) + (uint16_t)ConvertBitIntoBytes(&input[128], 8); //LSB //128
//this works okay for example of driver driving due west at the speed limit of the road (fluke?)
uint16_t rangle = (uint16_t)ConvertBitIntoBytes(&input[120], 8); //120,8
float fspeed = (float)rspeed;
float fangle = (float)rangle;
fspeed /= 255.0f; //unit value of 1 bit
fspeed *= 1.56f; //this is based on an observation of a driver moving approx 210 meters in about 8 seconds and this makes it just under the speed limit on the road there
// fangle *= 360.0f/255.0f; //unit value of 1 bit
fangle *= 2.0f; //may exceed 360 degrees as is (use %)
int s, a = 0;
s = (int)fspeed * 3.6;
a = (int)fangle % 360;
//fix and quality indicators?
uint8_t fix = input[147]; UNUSED(fix);
uint8_t quality = (uint16_t)ConvertBitIntoBytes(&input[148], 3); UNUSED(quality);
//timestamp (16-bit value w/ appended 17th bit to MSB)
uint32_t rtime = (uint32_t)ConvertBitIntoBytes(&input[104], 16); //seconds since midnight since last GPS fix (whatever the radio has as internal time)
rtime |= input[144] << 16; //test appending this as bit 17 (observed this bit set after the afternoon 0xFFFF rollover)
uint32_t thour = rtime / 3600;
uint32_t tmin = (rtime % 3600) / 60;
uint32_t tsec = (rtime % 3600) % 60;
float lat_dec = 0.0f;
float lon_dec = 0.0f;
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
//This appears to be similar to the NMEA GPGGA format (DDmm.mm) but
//octets are ordered in least significant to most significant value
lat_mmin = (uint16_t)ConvertBitIntoBytes(&input[40], 16); //? bits required, but grabbing two octets
lat_min = (uint8_t)ConvertBitIntoBytes(&input[58], 6); //6 bits required to get 60
lat_deg = (uint8_t)ConvertBitIntoBytes(&input[65], 7); //7 bits required to get 90
lat_sign = input[72]; //64
lon_mmin = (uint16_t)ConvertBitIntoBytes(&input[72], 16); //? bits required, but grabbing two octets
lon_min = (uint8_t)ConvertBitIntoBytes(&input[90], 6); //6 bits required to get 60
lon_deg = (uint8_t)ConvertBitIntoBytes(&input[96], 8); //8 bits required to get 180
lon_sign = input[88]; //88, unsure of a correct location, but on the sample with 0 minutes, this lonely bit was flagged on
int src = 0;
if (slot == 0) src = state->lastsrc;
if (slot == 1) src = state->lastsrcR;
//calculate decimal representation (was a pain to figure out the sub minute values)
lat_dec = ( (float)lat_deg + ((float)lat_min/60.0f) + ((float)lat_mmin/600000.0f) );
lon_dec = ( (float)lon_deg + ((float)lon_min/60.0f) + ((float)lon_mmin/600000.0f) );
if (lat_sign)
lat_dec *= -1.0f;
if (lon_sign)
lon_dec *= -1.0f;
//line break
fprintf (stderr, "\n");
fprintf (stderr, " GPS: %f%s, %f%s;", lat_dec, deg_glyph, lon_dec, deg_glyph);
//gps fix time
// fprintf (stderr, " RT: %05X;", rtime); //debug
fprintf (stderr, " LTS: %02d:%02d:%02d UTC;", thour, tmin, tsec); //last time synced to GPS
//speed and direction
// fprintf (stderr, " RSPD: %04X;", rspeed); //debug
// fprintf (stderr, " RANG: %02X;", rangle); //debug
// fprintf (stderr, " MPS: %06.02f;", fspeed);
// fprintf (stderr, " KPH: %06.02f;", fspeed * 3.6f);
// fprintf (stderr, " MPH: %06.02f;", fspeed * 2.2369f);
fprintf (stderr, " DIR: %03d%s;", a, deg_glyph);
// fprintf (stderr, " FIX: %d", fix);
// fprintf (stderr, " QLT: %02d", quality);
// fprintf (stderr, " SRC: %08d;", src);
//save to array for ncurses
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", lat_dec, deg_glyph, lon_dec, deg_glyph);
//save to LRRP report for mapping/logging
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", datestr );
fprintf (pFile, "%s\t", timestr );
fprintf (pFile, "%08d\t", src);
fprintf (pFile, "%.6lf\t", lat_dec);
fprintf (pFile, "%.6lf\t", lon_dec);
fprintf (pFile, "%d\t ", s);
fprintf (pFile, "%d\t ", a);
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
//not entirely convinced on some of these calcs (speed, angle, and TS) but sure these bits
//are actual speed/direction/timestamps judging from what the coordinates show on a map
}
//externalize embedded GPS - Confirmed working now on NE, NW, SE, and SW coordinates
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
{
UNUSED(opts);
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Embedded GPS:");
uint8_t slot = state->currentslot;
uint8_t pf = lc_bits[0];
uint8_t res_a = lc_bits[1];
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4);
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 3);
UNUSED2(res_a, res_b);
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
uint32_t lon_sign = lc_bits[23];
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24);
uint32_t lat_sign = lc_bits[48];
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
double lon_sf = 1.0f; //float value we can multiple longitude with
double lat_sf = 1.0f; //float value we can multiple latitude with
double lat_unit = (double)180/ pow (2.0, 24); //180 divided by 2^24
double lon_unit = (double)360/ pow (2.0, 25); //360 divided by 2^25
char latstr[3];
char lonstr[3];
sprintf (latstr, "%s", "N");
sprintf (lonstr, "%s", "E");
//run calculations and print
//7.2.16 and 7.2.17 (two's compliment)
double latitude = 0;
double longitude = 0;
if (pf) fprintf (stderr, " Protected");
else
{
if (lat_sign)
{
lat = 0x800001 - lat;
sprintf (latstr, "%s", "S");
lat_sf = -1.0f;
}
latitude = ((double)lat * lat_unit);
if (lon_sign)
{
lon = 0x1000001 - lon;
sprintf (lonstr, "%s", "W");
lon_sf = -1.0f;
}
longitude = ((double)lon * lon_unit);
//sanity check
if (abs (latitude) < 90 && abs(longitude) < 180)
{
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf)", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, lat_sf * latitude, lon_sf * longitude);
//7.2.15 Position Error
uint16_t position_error = 2 * pow(10, pos_err); //2 * 10^pos_err
if (pos_err == 0x7 ) fprintf (stderr, "\n Position Error: Unknown or Invalid");
else fprintf (stderr, "\n Position Error: Less than %dm", position_error);
//save to array for ncurses
if (pos_err != 0x7)
{
sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Err: %dm", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, position_error);
}
else sprintf (state->dmr_embedded_gps[slot], "GPS: %.5lf%s%s %.5lf%s%s Unknown Pos Err", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr);
//save to LRRP report for mapping/logging
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", datestr );
fprintf (pFile, "%s\t", timestr );
fprintf (pFile, "%08d\t", src);
fprintf (pFile, "%.5lf\t", latitude);
fprintf (pFile, "%.5lf\t", longitude);
fprintf (pFile, "0\t " ); //zero for velocity
fprintf (pFile, "0\t " ); //zero for azimuth
fprintf (pFile, "\n");
fclose (pFile);
}
}
}
fprintf (stderr, "%s", KNRM);
}
//This Function has been redone and variables fixed to mirror SDRTrunk
//my earlier assumption that this was the same format as DMR Embedded GPS was incorrect
void apx_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " GPS:");
uint8_t slot = state->currentslot;
uint8_t pf = lc_bits[0];
uint8_t res_a = lc_bits[1];
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 7);
uint8_t expired = lc_bits[23]; //this bit seems to indicate that the GPS coordinates are out of date or fresh
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
uint32_t lon_sign = lc_bits[48];
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[49], 23);
uint32_t lat_sign = lc_bits[24];
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[25], 23);
//todo: acquire more samples for additional validation
double lat_unit = 90.0f / 0x7FFFFF;
double lon_unit = 180.0f / 0x7FFFFF;
double lon_sf = 1.0f; //float value we can multiple longitude with
double lat_sf = 1.0f; //float value we can multiple latitude with
char latstr[3];
char lonstr[3];
char valid[9];
sprintf (latstr, "%s", "N");
sprintf (lonstr, "%s", "E");
sprintf (valid, "%s", "Current");
double latitude = 0;
double longitude = 0;
if (pf) fprintf (stderr, " Protected");
else
{
if (lat_sign)
{
sprintf (latstr, "%s", "S");
lat_sf = -1.0f;
}
latitude = ((double)lat * lat_unit);
if (lon_sign)
{
sprintf (lonstr, "%s", "W");
lon_sf = -1.0f;
}
longitude = ((double)lon * lon_unit);
//sanity check
if (abs (latitude) < 90 && abs(longitude) < 180)
{
fprintf (stderr, " Lat: %.5lf%s%s Lon: %.5lf%s%s (%.5lf, %.5lf) ", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, latitude * lat_sf, longitude * lon_sf);
if (expired)
{
fprintf (stderr, "Expired; ");
sprintf (valid, "%s", "Expired");
}
else if (!expired)
fprintf (stderr, "Current; ");
if (res_a)
fprintf (stderr, "RES_A: %d; ", res_a);
if (res_b)
fprintf (stderr, "RES_B: %02X; ", res_b);
//save to array for ncurses
sprintf (state->dmr_embedded_gps[slot], "GPS: %lf%s%s %lf%s%s %s", latitude, deg_glyph, latstr, longitude, deg_glyph, lonstr, valid);
//save to LRRP report for mapping/logging
FILE * pFile; //file pointer
if (opts->lrrp_file_output == 1)
{
int src = 0;
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", datestr );
fprintf (pFile, "%s\t", timestr );
fprintf (pFile, "%08d\t", src);
fprintf (pFile, "%.5lf\t", latitude);
fprintf (pFile, "%.5lf\t", longitude);
fprintf (pFile, "0\t " ); //zero for velocity
fprintf (pFile, "0\t " ); //zero for azimuth
fprintf (pFile, "\n");
fclose (pFile);
if (timestr != NULL)
{
free (timestr);
timestr = NULL;
}
if (datestr != NULL)
{
free (datestr);
datestr = NULL;
}
}
}
}
fprintf (stderr, "%s", KNRM);
}

259
src/dsd_import.c Normal file
View File

@@ -0,0 +1,259 @@
#include "dsd.h"
#define BSIZE 999
int csvGroupImport(dsd_opts * opts, dsd_state * state)
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->group_in_file);
//filename[1023] = '\0'; //necessary?
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open group file '%s'\n", filename);
exit(1);
}
int row_count = 0;
int field_count = 0;
long int group_number = 0; //local group number for array index value
UNUSED(group_number);
int i = 0;
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
if (field_count == 0)
{
//group_number = atol(field);
state->group_array[i].groupNumber = atol(field);
fprintf (stderr, "%ld, ", state->group_array[i].groupNumber);
}
if (field_count == 1)
{
strcpy(state->group_array[i].groupMode, field);
fprintf (stderr, "%s, ", state->group_array[i].groupMode);
}
if (field_count == 2)
{
strcpy(state->group_array[i].groupName, field);
fprintf (stderr, "%s ", state->group_array[i].groupName);
}
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "\n");
i++;
state->group_tally++;
}
fclose(fp);
return 0;
}
//LCN import for EDACS, migrated to channel map (channel map does both)
int csvLCNImport(dsd_opts * opts, dsd_state * state)
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->lcn_in_file);
//filename[1023] = '\0'; //necessary?
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open lcn file '%s'\n", filename);
//have this return -1 and handle it inside of main
exit(1);
}
int row_count = 0;
int field_count = 0;
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
state->trunk_lcn_freq[field_count] = atol (field);
state->lcn_freq_count++; //keep tally of number of Frequencies imported
fprintf (stderr, "LCN [%d] [%ld]", field_count+1, state->trunk_lcn_freq[field_count]);
fprintf (stderr, "\n");
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "LCN Count %d\n", state->lcn_freq_count);
}
fclose(fp);
return 0;
}
int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->chan_in_file);
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open channel map file '%s'\n", filename);
//have this return -1 and handle it inside of main
exit(1);
}
int row_count = 0;
int field_count = 0;
long int chan_number;
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
if (field_count == 0)
{
sscanf (field, "%ld", &chan_number);
}
if (field_count == 1)
{
sscanf (field, "%ld", &state->trunk_chan_map[chan_number]);
//adding this should be compatible with EDACS, test and obsolete the LCN Import function if desired
sscanf (field, "%ld", &state->trunk_lcn_freq[state->lcn_freq_count]);
state->lcn_freq_count++; //keep tally of number of Frequencies imported
}
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "Channel [%05ld] [%09ld]", chan_number, state->trunk_chan_map[chan_number]);
fprintf (stderr, "\n");
}
fclose(fp);
return 0;
}
//Decimal Variant of Key Import
int csvKeyImportDec(dsd_opts * opts, dsd_state * state) //multi-key support
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->key_in_file);
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open file '%s'\n", filename);
exit(1);
}
int row_count = 0;
int field_count = 0;
unsigned long long int keynumber = 0;
unsigned long long int keyvalue = 0;
uint16_t hash = 0;
uint8_t hash_bits[24];
memset (hash_bits, 0, sizeof(hash_bits));
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
if (field_count == 0)
{
sscanf (field, "%lld", &keynumber);
if (keynumber > 0xFFFF) //if larger than 16-bits, get its hash instead
{
keynumber = keynumber & 0xFFFFFF; //truncate to 24-bits (max allowed)
for (int i = 0; i < 24; i++)
{
hash_bits[i] = ((keynumber << i) & 0x800000) >> 23; //load into array for CRC16
}
hash = ComputeCrcCCITT16d (hash_bits, 24);
keynumber = hash & 0xFFFF; //make sure its no larger than 16-bits
fprintf (stderr, "Hashed ");
}
}
if (field_count == 1)
{
sscanf (field, "%lld", &keyvalue);
state->rkey_array[keynumber] = keyvalue & 0xFFFFFFFFFF; //doesn't exceed 40-bit value
}
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "Key [%03lld] [%05lld]", keynumber, state->rkey_array[keynumber]);
fprintf (stderr, "\n");
hash = 0;
}
fclose(fp);
return 0;
}
//Hex Variant of Key Import
int csvKeyImportHex(dsd_opts * opts, dsd_state * state) //key import for rc4 keys
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->key_in_file);
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open file '%s'\n", filename);
exit(1);
}
int row_count = 0;
int field_count = 0;
unsigned long long int keynumber;
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
if (field_count == 0)
{
sscanf (field, "%llX", &keynumber);
}
if (field_count == 1)
{
sscanf (field, "%llX", &state->rkey_array[keynumber]);
}
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "Key [%04llX] [%016llX]", keynumber, state->rkey_array[keynumber]);
fprintf (stderr, "\n");
}
fclose(fp);
return 0;
}

7
src/dsd_ks.c Normal file
View File

@@ -0,0 +1,7 @@
/*-------------------------------------------------------------------------------
* dsd_ks.c
* Placeholder File 6 -- This file is for temporary code storage
*
*
*
*-----------------------------------------------------------------------------*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

177
src/dsd_mbe2.c Normal file
View File

@@ -0,0 +1,177 @@
/*-------------------------------------------------------------------------------
*
*
*
* TODO: Fill me in'
*
*
* LWVMOBILE
* 2023-07 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
//new and simplified/organized ambe and imbe handling
//moving all audio handling and decryption to seperate files for simplicity (eventually)
#include "dsd.h"
//the initial functions will ONLY return demodulated ambe or imbe frames, THAT'S IT!
//decryption and audio handling etc will be handled at a different area
//using soft_demod will also allow for not compiling mbelib and also using a DVstick in the future
//P25p1 IMBE 7200 or AMBE+2 EFR
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;
}
//ProVoice IMBE 7100
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;
}
//AMBE+2 EHR
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);
}
//AMBE One Shot (DSTAR)
void soft_demod_ambe_dstar(dsd_opts * opts, dsd_state * state, char ambe_fr[4][24], char ambe_d[49])
{
mbe_processAmbe3600x2400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2,
state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->floating_point == 1)
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
else processAudio(opts, state);
}
//AMBE+2 One Shot (X2-TDMA)
void soft_demod_ambe_x2(dsd_opts * opts, dsd_state * state, char ambe_fr[4][24], char ambe_d[49])
{
mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2,
state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->floating_point == 1)
memcpy (state->f_l, state->audio_out_temp_buf, sizeof(state->f_l));
else processAudio(opts, state);
}
void soft_mbe (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
{
int i;
char ambe_d[49];
char imbe_d[88];
int slot = state->currentslot;
memset (ambe_d, 0, sizeof(ambe_d));
memset (imbe_d, 0, sizeof(imbe_d));
UNUSED(i);
//P25p1, YSF FR, NXDN EFR
if (state->synctype == 0 || state->synctype == 1)
{
soft_demod_imbe7200(state, imbe_fr, imbe_d);
//handle decryption here
//print IMBE frame
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
//send to playback here
}
//ProVoice
else if (state->synctype == 14 || state->synctype == 15)
{
soft_demod_imbe7100(state, imbe7100_fr, imbe_d);
//nothing to do
//convert to 7200
mbe_convertImbe7100to7200(imbe_d);
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
//send to playback here
}
//D-STAR AMBE
else if (state->synctype == 6 || state->synctype == 7)
{
soft_demod_ambe_dstar(opts, state, ambe_fr, ambe_d);
if(opts->payload == 1)
PrintAMBEData (opts, state, ambe_d);
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
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)
playSynthesizedVoiceSS(opts, state);
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
playSynthesizedVoiceFS(opts, state);
if (opts->wav_out_f != NULL)
writeSynthesizedVoice (opts, state);
if (opts->mbe_out_f != NULL)
saveAmbe2450Data (opts, state, ambe_d);
}
//X2-TDMA AMBE
else if (state->synctype >= 2 && state->synctype <= 5)
{
soft_demod_ambe_x2(opts, state, ambe_fr, ambe_d);
if(opts->payload == 1)
PrintAMBEData (opts, state, ambe_d);
if (opts->floating_point == 0 && opts->pulse_digi_out_channels == 1)
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)
playSynthesizedVoiceSS(opts, state);
if (opts->floating_point == 1 && opts->pulse_digi_out_channels == 2)
playSynthesizedVoiceFS(opts, state);
if (opts->wav_out_f != NULL)
writeSynthesizedVoice (opts, state);
if (opts->mbe_out_f != NULL)
saveAmbe2450Data (opts, state, ambe_d);
}
//AMBE+2 EHR (NXDN, DMR, P25p2, YSF VD/1)
else
{
soft_demod_ambe2_ehr (state, ambe_fr, ambe_d);
//decrypt here
if(opts->payload == 1)
PrintAMBEData (opts, state, ambe_d);
//make left or right channel decision
if (slot == 0)
{
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str,
ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
}
if (slot == 1)
{
mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR,
ambe_d, state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2, opts->uvquality);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,26 +2,59 @@
#include "dsd.h" #include "dsd.h"
#include "p25p1_heuristics.h" #include "p25p1_heuristics.h"
void //fixed the memory leak, but now random segfaults occur -- double free or corruption (out) or (!prev)
resetState (dsd_state * state) void resetState (dsd_state * state)
{ {
int i, j; int i;
//Dibit Buffer -- Free Allocated Memory
// free (state->dibit_buf);
//Dibit Buffer -- Memset/Init/Allocate Memory
// state->dibit_buf = malloc (sizeof (int) * 1000000); // state->dibit_buf = malloc (sizeof (int) * 1000000);
// state->dibit_buf_p = state->dibit_buf + 200;
// memset (state->dibit_buf, 0, sizeof (int) * 200); state->dibit_buf_p = state->dibit_buf + 200;
state->repeat = 0; //not sure yet memset (state->dibit_buf, 0, sizeof (int) * 200);
//state->audio_out_buf = malloc (sizeof (short) * 1000000); state->repeat = 0; //repeat frame?
//memset (state->audio_out_buf, 0, 100 * sizeof (short));
//state->audio_out_buf_p = state->audio_out_buf + 100; //Audio Buffer -- Free Allocated Memory
//state->audio_out_float_buf = malloc (sizeof (float) * 1000000); free (state->audio_out_buf);
//memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); free (state->audio_out_float_buf);
//state->audio_out_float_buf_p = state->audio_out_float_buf + 100; free (state->audio_out_bufR);
//state->audio_out_idx = 0; free (state->audio_out_float_bufR);
//state->audio_out_idx2 = 0;
//state->audio_out_temp_buf_p = state->audio_out_temp_buf; //Audio Buffer -- Memset/Init/Allocate Memory per slot
//state->wav_out_bytes = 0;
//slot 1
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
state->audio_out_buf = malloc (sizeof (short) * 1000000);
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_buf_p = state->audio_out_buf + 100;
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_idx = 0;
state->audio_out_idx2 = 0;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
//slot 2
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
state->audio_out_float_bufR = malloc (sizeof (float) * 1000000);
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
state->audio_out_buf_pR = state->audio_out_bufR + 100;
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
state->audio_out_idxR = 0;
state->audio_out_idx2R = 0;
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
//Sync
state->center = 0; state->center = 0;
state->jitter = -1; state->jitter = -1;
state->synctype = -1; state->synctype = -1;
@@ -31,76 +64,73 @@ resetState (dsd_state * state)
state->umid = 0; state->umid = 0;
state->minref = -12000; state->minref = -12000;
state->maxref = 12000; state->maxref = 12000;
state->lastsample = 0; state->lastsample = 0;
for (i = 0; i < 128; i++) for (i = 0; i < 128; i++)
{ {
state->sbuf[i] = 0; state->sbuf[i] = 0;
} }
state->sidx = 0; state->sidx = 0;
for (i = 0; i < 1024; i++) for (i = 0; i < 1024; i++)
{ {
state->maxbuf[i] = 15000; state->maxbuf[i] = 15000;
} }
for (i = 0; i < 1024; i++) for (i = 0; i < 1024; i++)
{ {
state->minbuf[i] = -15000; state->minbuf[i] = -15000;
} }
state->midx = 0; state->midx = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " ");
sprintf (state->ftype, " ");
state->symbolcnt = 0; state->symbolcnt = 0;
state->rf_mod = 0;
state->numflips = 0; state->numflips = 0;
state->lastsynctype = -1; state->lastsynctype = -1;
state->lastp25type = 0; state->lastp25type = 0;
state->offset = 0; state->offset = 0;
state->carrier = 0; state->carrier = 0;
for (i = 0; i < 25; i++)
{ //Reset Voice Errors in C0 and C1 (or remaining Codewords in IMBE)
for (j = 0; j < 16; j++)
{
state->tg[i][j] = 48;
}
}
state->tgcount = 0;
state->lasttg = 0;
state->lastsrc = 0;
state->nac = 0;
state->errs = 0; state->errs = 0;
state->errs2 = 0; state->errs2 = 0;
state->mbe_file_type = -1; state->errsR = 0;
state->errs2R = 0;
//Misc -- may not be needed
state->optind = 0; state->optind = 0;
state->numtdulc = 0; state->numtdulc = 0;
state->firstframe = 0; state->firstframe = 0;
sprintf (state->slot0light, " slot0 ");
sprintf (state->slot1light, " slot1 ");
state->aout_gain = 25;
memset (state->aout_max_buf, 0, sizeof (float) * 200);
state->aout_max_buf_p = state->aout_max_buf;
state->aout_max_buf_idx = 0;
state->samplesPerSymbol = 10;
state->symbolCenter = 4;
sprintf (state->algid, "________");
sprintf (state->keyid, "________________");
state->currentslot = 0;
state->cur_mp = malloc (sizeof (mbe_parms));
state->prev_mp = malloc (sizeof (mbe_parms));
state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->p25kid = 0;
state->debug_audio_errors = 0; //unsure if these are still used or ever were used,
state->debug_header_errors = 0; // memset (state->aout_max_buf, 0, sizeof (float) * 200);
state->debug_header_critical_errors = 0; // state->aout_max_buf_p = state->aout_max_buf;
// state->aout_max_buf_idx = 0;
state->nxdn_last_ran = 0; // //MBE Specific
// state->payload_algid = 0; // //free the memory before allocating it again -- may not use this
// state->payload_algidR = 0; // free (state->cur_mp);
state->dmr_encL = 0; // free (state->prev_mp);
state->dmr_encR = 0; // free (state->prev_mp_enhanced);
//each time you run this, it increses memory use by 4MB, massive memory leak // //memory allocation and init on mbe -- may not use this
//need to revisit this sometime and look into only resetting only the necesary items to let P25 switch between signals (C4FM or Wide) without needing a restart // state->cur_mp = malloc (sizeof (mbe_parms));
initialize_p25_heuristics(&state->p25_heuristics); //see if we want to re-init this or not, currently seems to cause memory leak when running over and over, mitigated with a reset flag // state->prev_mp = malloc (sizeof (mbe_parms));
// state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
// mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
//rest the heurestics, we want to do this on each tune, each RF frequency can deviate quite a bit in strength
initialize_p25_heuristics(&state->p25_heuristics);
initialize_p25_heuristics(&state->inv_p25_heuristics);
}
//simple function to reset the dibit buffer
void reset_dibit_buffer(dsd_state * state)
{
//Dibit Buffer -- Free Allocated Memory
// free (state->dibit_buf);
//Dibit Buffer -- Memset/Init/Allocate Memory
// state->dibit_buf = malloc (sizeof (int) * 1000000);
state->dibit_buf_p = state->dibit_buf + 200;
memset (state->dibit_buf, 0, sizeof (int) * 200);
} }

547
src/dsd_rigctl.c Normal file
View File

@@ -0,0 +1,547 @@
/*-------------------------------------------------------------------------------
* dsd_rigctl.c
* Simple RIGCTL Client for DSD (remote control of GQRX, SDR++, etc)
*
* Portions from https://github.com/neural75/gqrx-scanner
*
* LWVMOBILE
* 2022-10 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
//UDP Specific
#include <arpa/inet.h>
#define BUFSIZE 1024
#define FREQ_MAX 4096
#define SAVED_FREQ_MAX 1000
#define TAG_MAX 100
//
// error - wrapper for perror
//
void error(char *msg) {
perror(msg);
exit(0);
}
struct sockaddr_in address;
struct sockaddr_in addressA;
struct sockaddr_in addressM17;
//
// Connect
//
int Connect (char *hostname, int portno)
{
int sockfd;
struct sockaddr_in serveraddr;
struct hostent *server;
/* socket: create the socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
fprintf(stderr,"ERROR opening socket\n");
error("ERROR opening socket");
}
/* gethostbyname: get the server's DNS entry */
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
//exit(0);
return (0); //return 0, check on other end and configure pulse input
}
/* build the server's Internet address */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
/* connect: create a connection with the server */
if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
{
fprintf(stderr,"ERROR opening socket\n");
return (0);
}
return sockfd;
}
//
// Send
//
bool Send(int sockfd, char *buf)
{
int n;
n = write(sockfd, buf, strlen(buf));
if (n < 0)
error("ERROR writing to socket");
return true;
}
//
// Recv
//
bool Recv(int sockfd, char *buf)
{
int n;
n = read(sockfd, buf, BUFSIZE);
if (n < 0)
error("ERROR reading from socket");
buf[n]= '\0';
return true;
}
//
// GQRX Protocol
//
long int GetCurrentFreq(int sockfd)
{
long int freq = 0;
char buf[BUFSIZE];
char * ptr;
char * token;
Send(sockfd, "f\n");
Recv(sockfd, buf);
if (strcmp(buf, "RPRT 1") == 0 )
return freq;
token = strtok (buf, "\n");
freq = strtol (token, &ptr, 10);
// fprintf (stderr, "\nRIGCTL VFO Freq: [%ld]\n", freq);
return freq;
}
bool SetFreq(int sockfd, long int freq)
{
char buf[BUFSIZE];
sprintf (buf, "F %ld\n", freq);
Send(sockfd, buf);
Recv(sockfd, buf);
if (strcmp(buf, "RPRT 1\n") == 0 ) //sdr++ has a linebreak here, is that in all versions of the protocol?
return false;
return true;
}
bool SetModulation(int sockfd, int bandwidth)
{
char buf[BUFSIZE];
//the bandwidth is now a user/system based configurable variable
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 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;
}
bool GetSignalLevel(int sockfd, double *dBFS)
{
char buf[BUFSIZE];
Send(sockfd, "l\n");
Recv(sockfd, buf);
if (strcmp(buf, "RPRT 1") == 0 )
return false;
sscanf(buf, "%lf", dBFS);
*dBFS = round((*dBFS) * 10)/10;
if (*dBFS == 0.0)
return false;
return true;
}
bool GetSquelchLevel(int sockfd, double *dBFS)
{
char buf[BUFSIZE];
Send(sockfd, "l SQL\n");
Recv(sockfd, buf);
if (strcmp(buf, "RPRT 1") == 0 )
return false;
sscanf(buf, "%lf", dBFS);
*dBFS = round((*dBFS) * 10)/10;
return true;
}
bool SetSquelchLevel(int sockfd, double dBFS)
{
char buf[BUFSIZE];
sprintf (buf, "L SQL %f\n", dBFS);
Send(sockfd, buf);
Recv(sockfd, buf);
if (strcmp(buf, "RPRT 1") == 0 )
return false;
return true;
}
//
// GetSignalLevelEx
// Get a bunch of sample with some delay and calculate the mean value
//
bool GetSignalLevelEx(int sockfd, double *dBFS, int n_samp)
{
double temp_level;
*dBFS = 0;
int errors = 0;
for (int i = 0; i < n_samp; i++)
{
if ( GetSignalLevel(sockfd, &temp_level) )
*dBFS = *dBFS + temp_level;
else
errors++;
usleep(1000);
}
*dBFS = *dBFS / (n_samp - errors);
return true;
}
//shoe in UDP input connection here...still having issues that I don't know how to resolve
int UDPBind (char *hostname, int portno)
{
UNUSED(hostname);
int sockfd;
struct sockaddr_in serveraddr;
/* socket: create the socket */
//UDP socket
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd < 0)
{
fprintf(stderr,"ERROR opening UDP socket\n");
error("ERROR opening UDP socket");
}
/* build the server's Internet address */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY
serveraddr.sin_port = htons(portno);
//Bind socket to listening
if (bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {
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;
}
//going to leave this function available, even if completely switched over to rtl_dev_tune now, may be useful in the future
void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
{
UNUSED(state);
int handle;
unsigned short udp_port = opts->rtl_udp_port;
char data[5] = {0}; //data buffer size is 5 for UDP frequency tuning
struct sockaddr_in address;
uint32_t new_freq = frequency;
opts->rtlsdr_center_freq = new_freq; //for ncurses terminal display after rtl is started up
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
data[0] = 0;
data[1] = new_freq & 0xFF;
data[2] = (new_freq >> 8) & 0xFF;
data[3] = (new_freq >> 16) & 0xFF;
data[4] = (new_freq >> 24) & 0xFF;
memset((char * ) & address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //make user configurable later
address.sin_port = htons(udp_port);
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
close (handle); //close socket after sending.
}
void udp_socket_blaster(dsd_opts * opts, dsd_state * state, size_t nsam, void * data)
{
UNUSED(state);
size_t err = 0;
//listen with:
//short 8k/2
//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 320 -q -b 16 -r 8000 -c1 -t s16 -
//float 8k/2
//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 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));
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_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);
long int err = 0;
err = opts->udp_sockfd = 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_sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
if (err < 0)
{
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
return (err);
}
memset((char * ) & address, 0, sizeof(address));
address.sin_family = AF_INET;
err = address.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);
}
address.sin_port = htons(opts->udp_portno);
if (err < 0)
{
fprintf (stderr, " UDP htons Error %ld\n", err);
return (err);
}
return 0;
}
int udp_socket_connectA(dsd_opts * opts, dsd_state * state)
{
UNUSED(state);
long int err = 0;
err = opts->udp_sockfdA = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (err < 0)
{
fprintf (stderr, " UDP Socket Error %ld\n", err);
return (err);
}
// Don't think this is needed, but doesn't seem to hurt to keep it here either
int broadcastEnable = 1;
err = setsockopt(opts->udp_sockfdA, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
if (err < 0)
{
fprintf (stderr, " UDP Broadcast Set Error %ld\n", err);
return (err);
}
memset((char * ) & addressA, 0, sizeof(addressA));
addressA.sin_family = AF_INET;
err = addressA.sin_addr.s_addr = inet_addr(opts->udp_hostname);
if (err < 0) //error in this context reports back 32-bit inet_addr reversed order byte pairs
{
fprintf (stderr, " UDP inet_addr Error %ld\n", err);
return (err);
}
addressA.sin_port = htons(opts->udp_portno+2); //plus 2 to current port assignment for the analog port value
if (err < 0)
{
fprintf (stderr, " UDP htons Error %ld\n", err);
return (err);
}
return 0;
}
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

@@ -4,6 +4,7 @@
void void
openSerial (dsd_opts * opts, dsd_state * state) openSerial (dsd_opts * opts, dsd_state * state)
{ {
UNUSED(state);
struct termios tty; struct termios tty;
speed_t baud; speed_t baud;
@@ -73,6 +74,7 @@ resumeScan (dsd_opts * opts, dsd_state * state)
char cmd[16]; char cmd[16];
ssize_t result; ssize_t result;
UNUSED(result);
if (opts->serial_fd > 0) if (opts->serial_fd > 0)
{ {

View File

@@ -20,7 +20,7 @@
int int
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
{ {
short sample, sample2; short sample;
int i, sum, symbol, count; int i, sum, symbol, count;
ssize_t result; ssize_t result;
@@ -82,94 +82,330 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
} }
// Read the new sample from the input // Read the new sample from the input
if(opts->audio_in_type == 0) // && state->menuopen == 0 still not quite working if(opts->audio_in_type == 0) //pulse audio
{ {
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
//look into how processAudio handles playback, not sure if latency issues, or garbage sample values crash pulse when written }
// if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample != 0)
{
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here?
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
}
//playback is wrong, depends on samples_per_symbol, maybe make a buffer and store first?
//making buffer might also fix raw audio monitoring as well
if (opts->wav_out_file_raw[0] != 0) //if set for recording sample raw files
{
//writeRawSample (opts, state, sample);
}
else if (opts->audio_in_type == 5) //OSS
{
read (opts->audio_in_fd, &sample, 2);
} }
else if (opts->audio_in_type == 1) {
result = sf_read_short(opts->audio_in_file, &sample, 1); //stdin only, wav files moving to new number
//fprintf (stderr, ".."); else if (opts->audio_in_type == 1) //won't work in windows, needs posix pipe (mintty)
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767) {
{ result = sf_read_short(opts->audio_in_file, &sample, 1);
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here? if(result == 0)
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL); {
} sf_close(opts->audio_in_file);
if(result == 0) { cleanupAndExit (opts, state);
cleanupAndExit (opts, state); }
}
} }
//wav files, same but using seperate value so we can still manipulate ncurses menu
//since we can not worry about getch/stdin conflict
else if (opts->audio_in_type == 2) else if (opts->audio_in_type == 2)
{ {
#ifdef USE_PORTAUDIO result = sf_read_short(opts->audio_in_file, &sample, 1);
PaError err = Pa_ReadStream( opts->audio_in_pa_stream, &sample, 1 ); if(result == 0)
if( err != paNoError )
{ {
fprintf( stderr, "An error occured while using the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err ); sf_close(opts->audio_in_file);
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); fprintf (stderr, "\nEnd of %s\n", opts->audio_in_dev);
//open pulse input if we are pulse output AND using ncurses terminal
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
{
opts->audio_in_type = 0; //set input type
openPulseInput(opts); //open pulse input
}
//else cleanup and exit
else
{
cleanupAndExit(opts, state);
}
} }
}
#endif
}
else if (opts->audio_in_type == 3) else if (opts->audio_in_type == 3)
{ {
#ifdef USE_RTLSDR #ifdef USE_RTLSDR
// TODO: need to read demodulated stream here // Read demodulated stream here
// get_rtlsdr_sample(&sample); if (get_rtlsdr_sample(&sample, opts, state) < 0)
get_rtlsdr_sample(&sample, opts, state); cleanupAndExit(opts, state);
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767) //update root means square power level
{ opts->rtl_rms = rtl_return_rms();
state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here? sample *= opts->rtl_volume_multiplier;
pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
}
#endif #endif
} }
#ifdef TRACE_DSD //tcp socket input from SDR++ -- now with 1 retry if connection is broken
state->debug_sample_index++; else if (opts->audio_in_type == 8)
#endif {
#ifdef AERO_BUILD
result = sf_read_short(opts->tcp_file_in, &sample, 1);
if(result == 0) {
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
sleep (3); //halt all processing and wait 3 seconds
//attempt to reconnect to socket
opts->tcp_sockfd = 0;
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
if (opts->tcp_sockfd != 0)
{
//reset audio input stream
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
if(opts->tcp_file_in == NULL)
{
fprintf(stderr, "Error, couldn't Reconnect to TCP with libsndfile: %s\n", sf_strerror(NULL));
}
else fprintf (stderr, "TCP Socket Reconnected Successfully.\n");
}
else fprintf (stderr, "TCP Socket Connection Error.\n");
//now retry reading sample
result = sf_read_short(opts->tcp_file_in, &sample, 1);
if (result == 0) {
sf_close(opts->tcp_file_in);
opts->audio_in_type = 0; //set input type
opts->tcp_sockfd = 0; //added this line so we will know if it connected when using ncurses terminal keyboard shortcut
//openPulseInput(opts); //open pulse inpput
sample = 0; //zero sample on bad result, keep the ball rolling
//open pulse input if we are pulse output AND using ncurses terminal
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
{
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
fprintf (stderr, "Opening Pulse Audio Input.\n");
opts->audio_in_type = 0; //set input type
openPulseInput(opts); //open pulse input
}
//else cleanup and exit
else
{
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
fprintf (stderr, "Closing DSD-FME.\n");
cleanupAndExit(opts, state);
}
}
}
#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
sleep (3); //halt all processing and wait 3 seconds
//attempt to reconnect to socket
opts->tcp_sockfd = 0;
opts->tcp_sockfd = Connect(opts->tcp_hostname, opts->tcp_portno);
if (opts->tcp_sockfd != 0)
{
//reset audio input stream
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
if(opts->tcp_file_in == NULL)
{
fprintf(stderr, "Error, couldn't Reconnect to TCP with libsndfile: %s\n", sf_strerror(NULL));
}
else fprintf (stderr, "TCP Socket Reconnected Successfully.\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);
if (result == 0) {
sf_close(opts->tcp_file_in);
opts->audio_in_type = 0; //set input type
opts->tcp_sockfd = 0; //added this line so we will know if it connected when using ncurses terminal keyboard shortcut
openPulseInput(opts); //open pulse inpput
sample = 0; //zero sample on bad result, keep the ball rolling
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
}
}
#endif
}
//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)) /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)
state->analog_sample_counter = 959;
state->analog_out[state->analog_sample_counter++] = sample;
if (state->analog_sample_counter == 960)
{
//get an rms value if not using the rtl built in version
if (opts->audio_in_type != 3 && opts->monitor_input_audio == 1)
opts->rtl_rms = raw_rms(state->analog_out, 960, 1);
//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);
}
//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 && 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_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
//This one will only operate when OSS 48k1 (when both input and output are OSS audio)
if (opts->audio_out_type == 5 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
write (opts->audio_out_fd, state->analog_out, 960*2);
//STDOUT, but only when operating at 48k1 (no go just yet)
// if (opts->audio_out_type == 1 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
// write (opts->audio_out_fd, state->analog_out, 960*2);
//OSS 8k1 (no go just yet)
// if (opts->audio_out_type == 2 && opts->pulse_digi_rate_out == 48000 && opts->pulse_digi_out_channels == 1)
// write (opts->audio_out_fd, state->analog_out, 960*2);
//test updating the sync time, so we can hold here while trunking or scanning
state->last_cc_sync_time = time(NULL);
state->last_vc_sync_time = time(NULL);
}
//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;
}
}
if (have_sync == 1)
{
//sanity check to prevent an overflow
if (state->analog_sample_counter > 959)
state->analog_sample_counter = 959;
state->analog_out[state->analog_sample_counter++] = sample;
if (state->analog_sample_counter == 960)
{
//raw wav file saving -- file size on this blimps pretty fast 1 min ~= 6 MB; 1 hour ~= 360 MB;
if (opts->wav_out_raw != NULL)
{
sf_write_short(opts->wav_out_raw, state->analog_out, 960);
sf_write_sync (opts->wav_out_raw);
}
//zero out and reset counter
memset (state->analog_out, 0, sizeof(state->analog_out));
state->analog_sample_counter = 0;
}
}
// printf ("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR));
if (opts->use_cosine_filter) if (opts->use_cosine_filter)
{ {
if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33 || state->lastsynctype == 34) if ( (state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33
|| state->lastsynctype == 34 || state->lastsynctype == 30 || state->lastsynctype == 31)
{ {
sample = dmr_filter(sample); sample = dmr_filter(sample);
} }
else if (state->lastsynctype == 8 || state->lastsynctype == 9 || else if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17 ||
state->lastsynctype == 16 || state->lastsynctype == 17 || state->lastsynctype == 86 || state->lastsynctype == 87 || state->lastsynctype == 98 || state->lastsynctype == 99)
{
sample = m17_filter(sample);
}
else if (
state->lastsynctype == 20 || state->lastsynctype == 21 || state->lastsynctype == 20 || state->lastsynctype == 21 ||
state->lastsynctype == 22 || state->lastsynctype == 23 || state->lastsynctype == 22 || state->lastsynctype == 23 ||
state->lastsynctype == 24 || state->lastsynctype == 25 || state->lastsynctype == 24 || state->lastsynctype == 25 ||
state->lastsynctype == 26 || state->lastsynctype == 27 ) //|| state->lastsynctype == 26 || state->lastsynctype == 27 ||
//state->lastsynctype == 35 || state->lastsynctype == 36) //phase 2 state->lastsynctype == 28 || state->lastsynctype == 29 ) //||
//state->lastsynctype == 35 || state->lastsynctype == 36) //phase 2 C4FM disc tap input
{ {
if(state->samplesPerSymbol == 20) //if(state->samplesPerSymbol == 20)
if(opts->frame_nxdn48 == 1)
{ {
sample = nxdn_filter(sample); sample = nxdn_filter(sample);
} }
//else if (state->lastsynctype >= 20 && state->lastsynctype <=27) //this the right range?
else if (opts->frame_dpmr == 1)
{
sample = dpmr_filter(sample);
}
else if (state->samplesPerSymbol == 8) //phase 2 cqpsk else if (state->samplesPerSymbol == 8) //phase 2 cqpsk
{ {
//sample = dmr_filter(sample); //work on filter later //sample = dmr_filter(sample); //work on filter later
} }
else // the 12.5KHz NXDN filter is the same as the DMR filter else
{ {
sample = dmr_filter(sample); sample = dmr_filter(sample);
} }
@@ -254,7 +490,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
if (state->samplesPerSymbol == 20) //nxdn 4800 baud 2400 symbol rate if (state->samplesPerSymbol == 20) //nxdn 4800 baud 2400 symbol rate
{ {
if ((i >= 9) && (i <= 11)) // if ((i >= 9) && (i <= 11))
if ((i >= 7) && (i <= 13)) //7, 13 working good on multiple nxdn48, fewer random errors
{ {
sum += sample; sum += sample;
count++; count++;
@@ -273,12 +510,24 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
if (state->rf_mod == 0) if (state->rf_mod == 0)
{ {
// 0: C4FM modulation // 0: C4FM modulation
//EXPERIMENTAL: manipulate the left edge depending on sync type
//TODO: See if we can manipulate this a bit more based on AFC or similar type function
int l_edge = 2;
int r_edge = 2;
if ((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2)) if (state->synctype == 30 || state->synctype == 31) l_edge = 1; //YSF (need to test with new recordings at BW:12000)
{ else if ((state->lastsynctype >= 10 && state->lastsynctype <= 13) || state->lastsynctype == 32 || state->lastsynctype == 33) l_edge = 1;
sum += sample; else l_edge = 2; //P25 and NXDN96 perform better, DMR doesn't seem to care too much, but may favor 1 and not 2
count++;
} if ((i >= state->symbolCenter - l_edge) && (i <= state->symbolCenter + r_edge))
{
sum += sample;
count++;
}
//debug: show what was selected for the left edge
// fprintf (stderr, " L:%d", l_edge);
#ifdef TRACE_DSD #ifdef TRACE_DSD
if (i == state->symbolCenter - 1) { if (i == state->symbolCenter - 1) {
@@ -289,7 +538,18 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
} }
#endif #endif
} }
else else if (state->rf_mod == 1) //QPSK
{
//going one left, two on the right for QPSK, local system seems to favor that
//with same PPM setting used on C4FM, unsure if that works on other systems, just
//testing things now, not like QPSK works well here anyways
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 2)) //1,2
{
sum += sample;
count++;
}
}
else //GFSK
{ {
// 1: QPSK modulation // 1: QPSK modulation
// 2: GFSK modulation // 2: GFSK modulation
@@ -298,12 +558,23 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
// comes one sample too late. // comes one sample too late.
// This change makes a significant improvement in the BER, at least for // This change makes a significant improvement in the BER, at least for
// this file. // this file.
//if ((i == state->symbolCenter) || (i == state->symbolCenter + 1)) // if ((i == state->symbolCenter) || (i == state->symbolCenter + 1))
//GFSK should ideally be the same on the left and right, I would think
//I have not observed a system that would benefit from this alignment
if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1)) if ((i == state->symbolCenter - 1) || (i == state->symbolCenter + 1))
{ {
sum += sample; sum += sample;
count++; count++;
} }
//MISC Notes: When using RTL input, NXDN96 at BW:16 NXDN48 at BW:12
//I am beginning to suspect that RTL input is halfing the bandwidth, which
//is my original consclusion back when I was working on it last, unsure
//or the best course on that, could just be a rtl_fm flaw
//P25 may also work better at 16 as well now, hard to tell the difference since both are good
//DMR may not be any different on 12 or 16
//most likely though, this all will just depend on signal stregth more than anything
//as to how much BW you should set
#ifdef TRACE_DSD #ifdef TRACE_DSD
//if (i == state->symbolCenter) { //if (i == state->symbolCenter) {
@@ -356,6 +627,12 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
} }
#endif #endif
//test throttle on wav input files
if (opts->audio_in_type == 2)
{
if (state->use_throttle == 1) usleep(.003); //very environment specific, tuning to cygwin
}
//read op25/fme symbol bin files //read op25/fme symbol bin files
if (opts->audio_in_type == 4) if (opts->audio_in_type == 4)
{ {
@@ -369,28 +646,47 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
state->symbolc = fgetc(opts->symbolfile); state->symbolc = fgetc(opts->symbolfile);
//experimental throttle //experimental throttle
useconds_t stime = state->symbol_throttle;
if (state->use_throttle == 1) if (state->use_throttle == 1)
{ {
usleep(stime); // useconds_t stime = state->symbol_throttle;
// usleep(stime);
usleep(.003); //very environment specific, tuning to cygwin
} }
//fprintf(stderr, "%d", state->symbolc); //fprintf(stderr, "%d", state->symbolc);
if( feof(opts->symbolfile) ) if( feof(opts->symbolfile) )
{ {
opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted // opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
fclose(opts->symbolfile); fclose(opts->symbolfile);
openPulseInput(opts); 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
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
}
//else cleanup and exit
else
{
cleanupAndExit(opts, state);
}
} }
//assign symbol/dibit values based on modulation type //assign symbol/dibit values based on modulation type
if (state->rf_mod == 2) //GFSK if (state->rf_mod == 2) //GFSK
{ {
symbol = state->symbolc; symbol = state->symbolc;
if (state->symbolc == 0 && state->synctype >= 0) if (state->symbolc == 0 )
{ {
symbol = -3; //-1 symbol = -3; //-1
} }
if (state->symbolc == 1 && state->synctype >= 0) if (state->symbolc == 1 )
{ {
symbol = -1; //-3 symbol = -1; //-3
} }

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,132 +1,47 @@
/* /*-------------------------------------------------------------------------------
* Copyright (C) 2010 DSD Author * dsd_upsample.c
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) * Simplified 8k to 48k Upsample Functions
* Goodbye terrible ringing sound
*
*
* *
* Permission to use, copy, modify, and/or distribute this software for any * LWVMOBILE
* purpose with or without fee is hereby granted, provided that the above * 2024-03 DSD-FME Florida Man Edition
* copyright notice and this permission notice appear in all copies. *-----------------------------------------------------------------------------*/
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h" #include "dsd.h"
void //produce 6 short samples (48k) for every 1 short sample (8k)
upsample (dsd_state * state, float invalue) void upsampleS (short invalue, short prev, short outbuf[6])
{
UNUSED(prev);
for (int i = 0; i < 6; i++)
outbuf[i] = invalue;
}
//legacy 6x simplified version for the float_buf_p
void upsample (dsd_state * state, float invalue)
{ {
int i, j, sum; float *outbuf1;
float *outbuf1, c, d;
if (state->currentslot == 0 && state->dmr_stereo == 1) if (state->currentslot == 0 && state->dmr_stereo == 1)
{
outbuf1 = state->audio_out_float_buf_p; 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++;
if (state->currentslot == 1 && state->dmr_stereo == 1) else if (state->currentslot == 1 && state->dmr_stereo == 1)
{ outbuf1 = state->audio_out_float_buf_pR;
if (state->audio_out_idx2R > 24)
{ else if (state->dmr_stereo == 0)
// smoothing outbuf1 = state->audio_out_float_buf_p;
outbuf1 -= 16;
for (j = 0; j < 4; j++) *outbuf1 = invalue;
{ outbuf1++;
for (i = 0; i < 6; i++) *outbuf1 = invalue;
{ outbuf1++;
sum = 0; *outbuf1 = invalue;
outbuf1 -= 2; outbuf1++;
sum += (int)*outbuf1; *outbuf1 = invalue;
outbuf1 += 2; outbuf1++;
sum += (int)*outbuf1; *outbuf1 = invalue;
outbuf1 += 2; outbuf1++;
sum += (int)*outbuf1; *outbuf1 = invalue;
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;
}
}
}
}

View File

@@ -1,183 +1,397 @@
/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Note: D-STAR support is fairly complete at this point.
* The ambe3600x2450 decoder is similar butnot compatible with D-STAR voice frames.
* The dstar interleave pattern is different as well.
* GMSK modulation optimizations will also required to get a usable bit error
*/
#include "dsd.h" #include "dsd.h"
#include "dstar_const.h" #include "dstar_const.h"
#include "dstar_header.h" #include "fcs.h"
//simplified DSTAR
void processDSTAR(dsd_opts * opts, dsd_state * state)
{
uint8_t sd[480];
memset (sd, 0, sizeof(sd));
int i, j, dibit;
char ambe_fr[4][24];
const int *w, *x;
memset(ambe_fr, 0, sizeof(ambe_fr));
w = dW;
x = dX;
void processDSTAR(dsd_opts * opts, dsd_state * state) { //20 voice and 19 slow data frames (20th is frame sync)
// extracts AMBE frames from D-STAR voice frame for (j = 0; j < 21; j++)
int i, j, dibit; {
char ambe_fr[4][24];
unsigned char data[9];
unsigned int bits[4];
int framecount;
int sync_missed = 0;
unsigned char slowdata[4];
unsigned int bitbuffer = 0;
const int *w, *x;
//set carrier to 1 so ncurses will light up green memset(ambe_fr, 0, sizeof(ambe_fr));
state->carrier = 1; w = dW;
x = dX;
if (opts->errorbars == 1) { for (i = 0; i < 72; i++)
fprintf (stderr, "e:"); {
} dibit = getDibit(opts, state);
ambe_fr[*w][*x] = dibit & 1;
w++;
x++;
}
#ifdef DSTAR_DUMP soft_mbe(opts, state, NULL, ambe_fr, NULL);
fprintf (stderr, "\n");
#endif
if (state->synctype == 18) { if (j != 20)
framecount = 0; {
state->synctype = 6; for (i = 0; i < 24; i++)
} else if (state->synctype == 19) { {
framecount = 0; //slow data
state->synctype = 7; sd[(j*24)+i] = (uint8_t) getDibit(opts, state);
} else {
framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next
}
//why is this running in a loop for?
while (sync_missed < 3) {
memset(ambe_fr, 0, 96); }
// voice frame }
w = dW;
x = dX;
for (i = 0; i < 72; i++) { if (j == 20)
processDSTAR_SD(opts, state, sd);
dibit = getDibit(opts, state); //since we are in a long loop, use this to improve response time in ncurses
if (opts->use_ncurses_terminal == 1)
ncursesPrinter(opts, state);
bitbuffer <<= 1; }
if (dibit == 1) {
bitbuffer |= 0x01;
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
// we're slipping bits
fprintf (stderr, "sync in voice after i=%d, restarting\n", i);
//ugh just start over
i = 0;
w = dW;
x = dX;
framecount = 1;
continue;
}
ambe_fr[*w][*x] = (1 & dibit); fprintf (stderr, "\n");
w++;
x++; }
} void processDSTAR_HD(dsd_opts * opts, dsd_state * state)
{
processMbeFrame(opts, state, NULL, ambe_fr, NULL); int i;
int radioheaderbuffer[660];
// data frame - 24 bits
for (i = 73; i < 97; i++) { for (i = 0; i < 660; i++)
dibit = getDibit(opts, state); radioheaderbuffer[i] = getDibit(opts, state);
bitbuffer <<= 1;
if (dibit == 1) { dstar_header_decode(state, radioheaderbuffer);
bitbuffer |= 0x01; processDSTAR(opts, state);
}
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) { }
// looking if we're slipping bits
if (i != 96) { //first 24-bits of the larger scramble table
fprintf (stderr, "sync after i=%d\n", i); uint8_t sd_d[48] =
i = 96; {0,0,0,0, //0
} 1,1,1,0, //E
} 1,1,1,1, //F
} 0,0,1,0, //2
1,1,0,0, //C
slowdata[0] = (bitbuffer >> 16) & 0x000000FF; 1,0,0,1};//9
slowdata[1] = (bitbuffer >> 8) & 0x000000FF;
slowdata[2] = (bitbuffer) & 0x000000FF; //no so simplified Slow Data
slowdata[3] = 0; void processDSTAR_SD(dsd_opts * opts, dsd_state * state, uint8_t * sd)
{
if ((bitbuffer & 0x00FFFFFF) == 0x00AAB468) {
//We got sync! int i, j, len;
//fprintf (stderr, "Sync on framecount = %d\n", framecount); uint8_t sd_bytes[60]; //raw slow data packed into bytes
sync_missed = 0; uint8_t hd_bytes[60]; //storage for packed bytes sans the header indicator byte (0x55)
} else if ((bitbuffer & 0x00FFFFFF) == 0xAAAAAA) { uint8_t payload[60]; //unchanged copy of sd_bytes for payload printing
//End of transmission uint8_t rev[480]; //storage for reversing the bit order
fprintf (stderr, "End of transmission\n"); memset (sd_bytes, 0, sizeof(sd_bytes));
goto end; memset (hd_bytes, 0, sizeof(hd_bytes));
} else if (framecount % 21 == 0) { memset (payload, 0, sizeof(payload));
fprintf (stderr, "Missed sync on framecount = %d, value = %x/%x/%x\n",
framecount, slowdata[0], slowdata[1], slowdata[2]); //apply the descrambler
sync_missed++; for (i = 0; i < 480; i++)
} else if (framecount != 0 && (bitbuffer & 0x00FFFFFF) != 0x000000) { sd[i] ^= sd_d[i%24];
slowdata[0] ^= 0x70;
slowdata[1] ^= 0x4f; //reverse the bit order
slowdata[2] ^= 0x93; for (i = 0; i < 480; i++)
//fprintf (stderr, "unscrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] ); rev[i] = sd[479-i];
for (i = 0; i < 480; i++)
} else if (framecount == 0) { sd[i] = rev[i];
//fprintf (stderr, "never scrambled-%c\n",slowdata);
//fprintf (stderr, "never scrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] ); //load bytes by least significant byte to most significant byte
//as seen in "The Format of D-Star Slow Data" by Jonathan Naylor
} for (i = 0; i < 60; i++)
for (short int i = 0; i < 4; i++) sd_bytes[59-i] = (uint8_t)ConvertBitIntoBytes(&sd[i*8+0], 8);
{
if (slowdata[i] <= 0x7E && slowdata[i] >=0x20) //make a copy to payload that won't be altered
{ memcpy (payload, sd_bytes, sizeof(payload));
//fprintf (stderr, "%c", slowdata[i]);
} len = sd_bytes[0] & 0xF;
//else fprintf (stderr, "."); len += 1;
}
//fprintf (stderr, "\n"); //load payload bytes without the header indicator byte
framecount++; for (i = 0, j = 0; i < 50; i++)
{
//since we are in a while loop, run ncursesPrinter here. j++;
if (opts->use_ncurses_terminal == 1) hd_bytes[i] = sd_bytes[j];
{ if (j == len*1-1) j++;
ncursesPrinter(opts, state); if (j == len*2-1) j++;
} if (j == len*3-1) j++;
if (j == len*4-1) j++;
} //end while loop if (j == len*5-1) j++;
if (j == len*6-1) j++;
end: if (opts->errorbars == 1) { if (j == len*7-1) j++;
fprintf (stderr, "\n"); if (j == len*8-1) j++;
} if (j == len*9-1) j++;
} }
void processDSTAR_HD(dsd_opts * opts, dsd_state * state) { //works on header format -- may not work on others
uint16_t crc_ext = (hd_bytes[39] << 8) + hd_bytes[40];
int i, j; uint16_t crc_cmp = calc_fcs(hd_bytes, 39);
int radioheaderbuffer[660];
char str1[9];
for (j = 0; j < 660; j++) { char str2[9];
radioheaderbuffer[j] = getDibit(opts, state); char str3[9];
} char str4[13];
char strf[60];
// Note: These routines contain GPLed code. Remove if you object to that. char strt[60];
// Due to this, they are in a separate source file. memset (strf, 0x20, sizeof(strf));
dstar_header_decode(state, radioheaderbuffer); memset (strt, 0x20, sizeof(strf));
memcpy (str1, hd_bytes+3, 8);
//We officially have sync now, so just pass on to the above routine: memcpy (str2, hd_bytes+11, 8);
memcpy (str3, hd_bytes+19, 8);
processDSTAR(opts, state); memcpy (str4, hd_bytes+27, 12);
str1[8] = '\0';
str2[8] = '\0';
str3[8] = '\0';
str4[12] = '\0';
//safety check, don't want to load nasty values into the strings
for (i = 1; i < 60; i++)
{
//substitue non-ascii characters for spaces
if (sd_bytes[i] < 0x20)
sd_bytes[i] = 0x20;
else if (sd_bytes[i] > 0x7E)
sd_bytes[i] = 0x20;
//substitue non-ascii characters for spaces
if (hd_bytes[i] < 0x20)
hd_bytes[i] = 0x20;
else if (hd_bytes[i] > 0x7E)
hd_bytes[i] = 0x20;
//replace terminating ffffffff (repeating 0x66 values) with NULL (0x00)
if (i < 59)
{
if (sd_bytes[i] == 0x66 && sd_bytes[i+1] == 0x66)
sd_bytes[i] = 0x00;
if (hd_bytes[i] == 0x66 && hd_bytes[i+1] == 0x66)
hd_bytes[i] = 0x00;
}
if (i == 59 && sd_bytes[i] == 0x66)
sd_bytes[i] = 0x00;
if (i == 59 && hd_bytes[i] == 0x66)
hd_bytes[i] = 0x00;
}
memcpy (strf, sd_bytes+1, 58); //copy the entire thing as a string -- full
memcpy (strt, hd_bytes+1, 48); //copy the entire thing as a string -- truncated
strf[59] = '\0';
strt[59] = '\0';
char type[7]; char temp[8]; char tempa[8]; char chungus[80]; UNUSED(chungus);
memset (chungus, 0, sizeof(chungus));
memset (temp, 0, sizeof(temp));
memset (tempa, 0, sizeof(tempa));
memset (type, 0, sizeof(type));
memcpy (type, sd_bytes+1, 5);
type[6] = '\0';
if (sd_bytes[0] == 0x55) //header format
{
if (crc_cmp == crc_ext)
{
fprintf (stderr, " RPT 2: %s", str1);
fprintf (stderr, " RPT 1: %s", str2);
fprintf (stderr, " DST: %s", str3);
fprintf (stderr, " SRC: %s", str4);
//check flags for info
if (sd_bytes[1] & 0x80) fprintf (stderr, " DATA");
if (sd_bytes[1] & 0x40) fprintf (stderr, " REPEATER");
if (sd_bytes[1] & 0x20) fprintf (stderr, " INTERRUPTED");
if (sd_bytes[1] & 0x10) fprintf (stderr, " CONTROL SIGNAL");
if (sd_bytes[1] & 0x08) fprintf (stderr, " URGENT");
memcpy (state->dstar_rpt2, str1, sizeof(str1));
memcpy (state->dstar_rpt1, str2, sizeof(str2));
memcpy (state->dstar_dst, str3, sizeof(str3));
memcpy (state->dstar_src, str4, sizeof(str4));
}
else fprintf (stderr, " SLOW DATA - HEADER FORMAT (CRC ERR)");
}
else //any other format (text, aprs, etc)
{
//fixed-form at 5 bytes, evaluate
if (sd_bytes[0] == 0x35)
{
//might as well just dump both of these outputs
if (strcmp(type, "$$CRC") == 0) //APRS
{
memset (strt, 0x20, sizeof(strt)); //space fill
fprintf (stderr, " DATA: ");
for (i = 1; i < 59; i++)
{
if (i%6==0) i++;
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
{
fprintf (stderr, "%c", sd_bytes[i]);
// strt[i] = sd_bytes[i];
}
}
// strt[59] = '\0';
// memcpy (state->dstar_gps, strt, sizeof(strt));
}
if (strcmp(type, "$$CRC") == 0) //APRS
{
fprintf (stderr, "\n APRS - ");
sprintf (state->dstar_gps, "APRS - ");
uint8_t aprs[51];
int k = 0;
memset (aprs, 0, sizeof(aprs));
//reshuffle (yet again) into an easier format to manipulate for aprs
for (i = 1; i < 59; i++)
{
if (i % 6 == 0 ) i++;
aprs[k] = sd_bytes[i];
if ( (aprs[k] > 0x19) && (aprs[k] < 0x7F) )
aprs[i] = 0x20;
k++;
}
//start by looking for the ! exclamation point token
int start = -1;
for (i = 30; i < 40; i++)
{
if (aprs[i] == 0x21)
{
start = i+1;
break;
}
}
//if not found, then skip (bad decode)
if (start == -1)
goto SKIP;
//debug
// fprintf (stderr, "S: %d; ", start); //38, or 39
//LAT
memcpy (temp, aprs+start, 2);
start += 2;
fprintf (stderr, "Lat: %sd ", temp);
strcat (state->dstar_gps, "Lat: ");
strcat (state->dstar_gps, temp);
strcat (state->dstar_gps, "d ");
memcpy (temp, aprs+start, 2);
start += 3;
fprintf (stderr, "%sm ", temp);
strcat (state->dstar_gps, temp);
strcat (state->dstar_gps, "m ");
memcpy (temp, aprs+start, 2);
start+=1;
fprintf (stderr, "%ss ", temp);
strcat (state->dstar_gps, temp);
strcat (state->dstar_gps, "s ");
fprintf (stderr, "%c", aprs[start]);
if (sd_bytes[start] == 0x4E)
strcat (state->dstar_gps, "N ");
else if (sd_bytes[start] == 0x53)
strcat (state->dstar_gps, "S ");
fprintf (stderr, "; ");
//LON
start += 3;
memcpy (tempa, aprs+start, 3);
start += 3;
fprintf (stderr, "Lon: %sd ", tempa);
strcat (state->dstar_gps, "Lon: ");
strcat (state->dstar_gps, tempa);
strcat (state->dstar_gps, "d ");
memcpy (temp, aprs+start, 2);
start += 3; //3
fprintf (stderr, "%sm ", temp);
strcat (state->dstar_gps, temp);
strcat (state->dstar_gps, "m ");
memcpy (temp, aprs+start, 2);
start += 2;
fprintf (stderr, "%ss ", temp);
strcat (state->dstar_gps, temp);
strcat (state->dstar_gps, "s ");
fprintf (stderr, "%c", aprs[start]);
if (aprs[start] == 0x45)
strcat (state->dstar_gps, "E ");
else if (aprs[start] == 0x57)
strcat (state->dstar_gps, "W ");
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 ");
SKIP: ; //do nothing
//this seems to work okay with a few samples, but wouldn't be surprised if it broke down
//randomly on different users, depending on location and what else in in $$CRC
}
else
{
// fprintf (stderr, " %s: ", type);
memset (strt, 0x20, sizeof(strt)); //space fill
fprintf (stderr, " TEXT: ");
for (i = 1; i < 59; i++)
{
if (i%6==0) i++;
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
{
fprintf (stderr, "%c", sd_bytes[i]);
strt[i] = sd_bytes[i];
}
}
strt[59] = '\0';
memcpy (state->dstar_txt, strt, sizeof(strt));
}
}
//free-form text at 5 bytes, truncate every 6th position
else if (sd_bytes[0] == 0x40)
{
memset (strt, 0x20, sizeof(strt)); //space fill
fprintf (stderr, " TEXT: ");
for (i = 1; i < 59; i++)
{
if (i%6==0) i++;
if ( (sd_bytes[i] > 0x19) && (sd_bytes[i] < 0x7F) )
{
fprintf (stderr, "%c", sd_bytes[i]);
strt[i] = sd_bytes[i];
}
}
strt[59] = '\0';
memcpy (state->dstar_txt, strt, sizeof(strt));
}
//anything else
else //print entire thing
{
fprintf (stderr, " _UNK:");
fprintf (stderr, " %s", strf);
// memcpy (state->dstar_txt, strf, sizeof(strf)); //don't copy the unknown garbo strings
}
}
if (opts->payload == 1)
{
fprintf (stderr, "\n SD: ");
for (i = 0; i < 60; i++)
{
fprintf (stderr, "[%02X]", payload[i]);
if (i == 29) fprintf (stderr, "\n ");
}
if (crc_cmp != crc_ext)
fprintf (stderr, "CRC - EXT: %04X CMP: %04X", crc_ext, crc_cmp);
}
} }

View File

@@ -1,8 +1,8 @@
/* /*
* *
* This code is taken largely from on1arf's GMSK code. Original copyright below: * This code is taken largely from on1arf's GMSK code. Original copyright below:
* *
* *
* Copyright (C) 2011 by Kristoff Bonne, ON1ARF * Copyright (C) 2011 by Kristoff Bonne, ON1ARF
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -13,75 +13,84 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
*/ */
#include "fcs.h"
#include "descramble.h" #include "descramble.h"
#include "dstar_header.h" #include "dstar_header.h"
#include "dsd.h" #include "dsd.h"
// #include "fcs.h" //error: multiple definition of `calc_fcs'; CMakeFiles/dsd-fme.dir/src/dstar.c.o:dstar.c:(.text+0x0): first defined here
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]) { void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660])
{
int radioheaderbuffer2[660]; int radioheaderbuffer2[660];
unsigned char radioheader[41]; char radioheader[41];
int octetcount, bitcount, loop; int octetcount, bitcount, loop;
unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; unsigned char bit2octet[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned int FCSinheader;
unsigned int FCScalculated;
int len;
scramble(radioheaderbuffer, radioheaderbuffer2); scramble(radioheaderbuffer, radioheaderbuffer2);
deinterleave(radioheaderbuffer2, radioheaderbuffer); deinterleave(radioheaderbuffer2, radioheaderbuffer);
len = FECdecoder(radioheaderbuffer, radioheaderbuffer2); FECdecoder(radioheaderbuffer, radioheaderbuffer2);
memset(radioheader, 0, 41); memset(radioheader, 0, 41);
//memset(state->dstarradioheader, 0, 41);
// note we receive 330 bits, but we only use 328 of them (41 octets) // note we receive 330 bits, but we only use 328 of them (41 octets)
// bits 329 and 330 are unused // bits 329 and 330 are unused
octetcount = 0; octetcount = 0;
bitcount = 0; bitcount = 0;
for (loop = 0; loop < 328; loop++) { for (loop = 0; loop < 328; loop++)
if (radioheaderbuffer2[loop]) { {
if (radioheaderbuffer2[loop])
radioheader[octetcount] |= bit2octet[bitcount]; radioheader[octetcount] |= bit2octet[bitcount];
};
bitcount++; bitcount++;
// increase octetcounter and reset bitcounter every 8 bits // increase octetcounter and reset bitcounter every 8 bits
if (bitcount >= 8) { if (bitcount >= 8)
{
octetcount++; octetcount++;
bitcount = 0; bitcount = 0;
} }
} }
//state->dstarradioheader = radioheader;
for (short i = 0; i < 41; i++) char str1[9];
{ char str2[9];
state->dstarradioheader[i] = radioheader[i]; char str3[9];
} char str4[13];
memcpy (str1, radioheader+3, 8);
memcpy (str2, radioheader+11, 8);
memcpy (str3, radioheader+19, 8);
memcpy (str4, radioheader+27, 12);
// print header str1[8] = '\0';
fprintf (stderr, "\nDSTAR HEADER: "); str2[8] = '\0';
//fprintf (stderr, "FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0], str3[8] = '\0';
// radioheader[1], radioheader[2]); str4[12] = '\0';
fprintf (stderr, "RPT 2: %c%c%c%c%c%c%c%c ", radioheader[3], radioheader[4],
radioheader[5], radioheader[6], radioheader[7], radioheader[8],
radioheader[9], radioheader[10]);
fprintf (stderr, "RPT 1: %c%c%c%c%c%c%c%c ", radioheader[11], radioheader[12],
radioheader[13], radioheader[14], radioheader[15], radioheader[16],
radioheader[17], radioheader[18]);
fprintf (stderr, "YOUR: %c%c%c%c%c%c%c%c ", radioheader[19], radioheader[20],
radioheader[21], radioheader[22], radioheader[23], radioheader[24],
radioheader[25], radioheader[26]);
fprintf (stderr, "MY: %c%c%c%c%c%c%c%c/%c%c%c%c\n", radioheader[27],
radioheader[28], radioheader[29], radioheader[30], radioheader[31],
radioheader[32], radioheader[33], radioheader[34], radioheader[35],
radioheader[36], radioheader[37], radioheader[38]);
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF; //TODO: Add fcs_calc to header as well
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39); // uint16_t crc_ext = (radioheader[39] << 8) + radioheader[40];
//fprintf (stderr, "Check sum = %04X ", FCSinheader); // uint16_t crc_cmp = calc_fcs(radioheader, 39);
//if (FCSinheader == FCScalculated) {
// fprintf (stderr, "(OK)\n"); //debug
//} else { // fprintf (stderr, "\n HD: ");
// fprintf (stderr, "(NOT OK- Calculated FCS = %04X)\n", FCScalculated); // for (int i = 0; i < 40; i++)
//}; // end else - if // fprintf (stderr, "%02X ", radioheader[i]);
// fprintf (stderr, "\n");
fprintf (stderr, " RPT 2: %s", str1);
fprintf (stderr, " RPT 1: %s", str2);
fprintf (stderr, " DST: %s", str3);
fprintf (stderr, " SRC: %s", str4);
//check flags for info
if (radioheader[0] & 0x80) fprintf (stderr, " DATA");
if (radioheader[0] & 0x40) fprintf (stderr, " REPEATER");
if (radioheader[0] & 0x20) fprintf (stderr, " INTERRUPTED");
if (radioheader[0] & 0x10) fprintf (stderr, " CONTROL SIGNAL");
if (radioheader[0] & 0x08) fprintf (stderr, " URGENT");
memcpy (state->dstar_rpt2, str1, sizeof(str1));
memcpy (state->dstar_rpt1, str2, sizeof(str2));
memcpy (state->dstar_dst, str3, sizeof(str3));
memcpy (state->dstar_src, str4, sizeof(str4));
//TODO: Call History for DSTAR
} }

519
src/edacs-bch3.c Normal file
View File

@@ -0,0 +1,519 @@
/*
* File: bch3.h
* Title: Encoder/decoder for binary BCH codes in C (Version 3.1)
* Author: Robert Morelos-Zaragoza
* Date: August 1994-June 13, 1997
* Mod: December 14, 2021, for EDACS-FM BCH Polynomial Error Generation and Detection
* Mod2: October 2022, for DSD-FME port of EDACS-FM
* Source: www.eccpage.com
*
* =============== Encoder/Decoder for binary BCH codes in C =================
*
* Version 1: Original program. The user provides the generator polynomial
* of the code (cumbersome!).
* Version 2: Computes the generator polynomial of the code.
* Version 3: No need to input the coefficients of a primitive polynomial of
* degree m, used to construct the Galois Field GF(2**m). The
* program now works for any binary BCH code of length such that:
* 2**(m-1) - 1 < length <= 2**m - 1
*
* Note: You may have to change the size of the arrays to make it work.
*
* The encoding and decoding methods used in this program are based on the
* book "Error Control Coding: Fundamentals and Applications", by Lin and
* Costello, Prentice Hall, 1983.
*
* Thanks to Patrick Boyle (pboyle@era.com) for his observation that 'bch2.c'
* did not work for lengths other than 2**m-1 which led to this new version.
* Portions of this program are from 'rs.c', a Reed-Solomon encoder/decoder
* in C, written by Simon Rockliff (simon@augean.ua.oz.au) on 21/9/89. The
* previous version of the BCH encoder/decoder in C, 'bch2.c', was written by
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) on 5/19/92.
*
* NOTE:
* The author is not responsible for any malfunctioning of
* this program, nor for any damage caused by it. Please include the
* original program along with these comments in any redistribution.
*
* For more information, suggestions, or other ideas on implementing error
* correcting codes, please contact me at:
*
* Robert Morelos-Zaragoza
* 5120 Woodway, Suite 7036
* Houston, Texas 77056
*
* email: r.morelos-zaragoza@ieee.org
*
* COPYRIGHT NOTICE: This computer program is free for non-commercial purposes.
* You may implement this program for any non-commercial application. You may
* also implement this program for commercial purposes, provided that you
* obtain my written permission. Any modification of this program is covered
* by this copyright.
*
* == Copyright (c) 1994-7, Robert Morelos-Zaragoza. All rights reserved. ==
*
* m = order of the Galois field GF(2**m)
* n = 2**m - 1 = size of the multiplicative group of GF(2**m)
* length = length of the BCH code
* t = error correcting capability (max. no. of errors the code corrects)
* d = 2*t + 1 = designed min. distance = no. of consecutive roots of g(x) + 1
* k = n - deg(g(x)) = dimension (no. of information bits/codeword) of the code
* p[] = coefficients of a primitive polynomial used to generate GF(2**m)
* g[] = coefficients of the generator polynomial, g(x)
* alpha_to [] = log table of GF(2**m)
* index_of[] = antilog table of GF(2**m)
* ddata[] = information bits = coefficients of data polynomial, i(x)
* bb[] = coefficients of redundancy polynomial x^(length-k) i(x) modulo g(x)
* numerr = number of errors
* errpos[] = error positions
* recd[] = coefficients of the received polynomial
* decerror = number of decoding errors (in _message_ positions)
*
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int m, n, length, k, t, d;
int p[21];
int alpha_to[1048576], index_of[1048576], g[548576];
int recd[1048576], ddata[1048576], bb[548576];
int seed;
int numerr, errpos[1024], decerror = 0;
void
read_p()
/*
* Read m, the degree of a primitive polynomial p(x) used to compute the
* Galois field GF(2**m). Get precomputed coefficients p[] of p(x). Read
* the code length.
*/
{
int i, ninf;
do {
m = 6;
} while ( !(m>1) || !(m<21) );
for (i=1; i<m; i++)
p[i] = 0;
p[0] = p[m] = 1;
if (m == 2) p[1] = 1;
else if (m == 3) p[1] = 1;
else if (m == 4) p[1] = 1;
else if (m == 5) p[2] = 1;
else if (m == 6) p[1] = 1;
else if (m == 7) p[1] = 1;
else if (m == 8) p[4] = p[5] = p[6] = 1;
else if (m == 9) p[4] = 1;
else if (m == 10) p[3] = 1;
else if (m == 11) p[2] = 1;
else if (m == 12) p[3] = p[4] = p[7] = 1;
else if (m == 13) p[1] = p[3] = p[4] = 1;
else if (m == 14) p[1] = p[11] = p[12] = 1;
else if (m == 15) p[1] = 1;
else if (m == 16) p[2] = p[3] = p[5] = 1;
else if (m == 17) p[3] = 1;
else if (m == 18) p[7] = 1;
else if (m == 19) p[1] = p[5] = p[6] = 1;
else if (m == 20) p[3] = 1;
n = 1;
for (i = 0; i <= m; i++) {
n *= 2;
}
n = n / 2 - 1;
ninf = (n + 1) / 2 - 1;
do {
length = 40;
} while ( !((length <= n)&&(length>ninf)) );
}
void
generate_gf()
/*
* Generate field GF(2**m) from the irreducible polynomial p(X) with
* coefficients in p[0]..p[m].
*
* Lookup tables:
* index->polynomial form: alpha_to[] contains j=alpha^i;
* polynomial form -> index form: index_of[j=alpha^i] = i
*
* alpha=2 is the primitive element of GF(2**m)
*/
{
register int i, mask;
mask = 1;
alpha_to[m] = 0;
for (i = 0; i < m; i++) {
alpha_to[i] = mask;
index_of[alpha_to[i]] = i;
if (p[i] != 0)
alpha_to[m] ^= mask;
mask <<= 1;
}
index_of[alpha_to[m]] = m;
mask >>= 1;
for (i = m + 1; i < n; i++) {
if (alpha_to[i - 1] >= mask)
alpha_to[i] = alpha_to[m] ^ ((alpha_to[i - 1] ^ mask) << 1);
else
alpha_to[i] = alpha_to[i - 1] << 1;
index_of[alpha_to[i]] = i;
}
index_of[0] = -1;
}
void
gen_poly()
/*
* Compute the generator polynomial of a binary BCH code. Fist generate the
* cycle sets modulo 2**m - 1, cycle[][] = (i, 2*i, 4*i, ..., 2^l*i). Then
* determine those cycle sets that contain integers in the set of (d-1)
* consecutive integers {1..(d-1)}. The generator polynomial is calculated
* as the product of linear factors of the form (x+alpha^i), for every i in
* the above cycle sets.
*/
{
register int ii, jj, ll, kaux;
register int test, aux, nocycles, root, noterms, rdncy;
int cycle[1024][21], size[1024], min[1024], zeros[1024];
/* Generate cycle sets modulo n, n = 2**m - 1 */
cycle[0][0] = 0;
size[0] = 1;
cycle[1][0] = 1;
size[1] = 1;
jj = 1; /* cycle set index */
if (m > 9) {
}
do {
/* Generate the jj-th cycle set */
ii = 0;
do {
ii++;
cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % n;
size[jj]++;
aux = (cycle[jj][ii] * 2) % n;
} while (aux != cycle[jj][0]);
/* Next cycle set representative */
ll = 0;
do {
ll++;
test = 0;
for (ii = 1; ((ii <= jj) && (!test)); ii++)
/* Examine previous cycle sets */
for (kaux = 0; ((kaux < size[ii]) && (!test)); kaux++)
if (ll == cycle[ii][kaux])
test = 1;
} while ((test) && (ll < (n - 1)));
if (!(test)) {
jj++; /* next cycle set index */
cycle[jj][0] = ll;
size[jj] = 1;
}
} while (ll < (n - 1));
nocycles = jj; /* number of cycle sets modulo n */
t = 2;
d = 2 * t + 1;
/* Search for roots 1, 2, ..., d-1 in cycle sets */
kaux = 0;
rdncy = 0;
for (ii = 1; ii <= nocycles; ii++) {
min[kaux] = 0;
test = 0;
for (jj = 0; ((jj < size[ii]) && (!test)); jj++)
for (root = 1; ((root < d) && (!test)); root++)
if (root == cycle[ii][jj]) {
test = 1;
min[kaux] = ii;
}
if (min[kaux]) {
rdncy += size[min[kaux]];
kaux++;
}
}
noterms = kaux;
kaux = 1;
for (ii = 0; ii < noterms; ii++)
for (jj = 0; jj < size[min[ii]]; jj++) {
zeros[kaux] = cycle[min[ii]][jj];
kaux++;
}
k = length - rdncy;
if (k<0)
{
exit(0);
}
/* Compute the generator polynomial */
g[0] = alpha_to[zeros[1]];
g[1] = 1; /* g(x) = (X + zeros[1]) initially */
for (ii = 2; ii <= rdncy; ii++) {
g[ii] = 1;
for (jj = ii - 1; jj > 0; jj--)
if (g[jj] != 0)
g[jj] = g[jj - 1] ^ alpha_to[(index_of[g[jj]] + zeros[ii]) % n];
else
g[jj] = g[jj - 1];
g[0] = alpha_to[(index_of[g[0]] + zeros[ii]) % n];
}
}
void
encode_bch()
/*
* Compute redundacy bb[], the coefficients of b(x). The redundancy
* polynomial b(x) is the remainder after dividing x^(length-k)*ddata(x)
* by the generator polynomial g(x).
*/
{
register int i, j;
register int feedback;
for (i = 0; i < length - k; i++)
bb[i] = 0;
for (i = k - 1; i >= 0; i--) {
feedback = ddata[i] ^ bb[length - k - 1];
if (feedback != 0) {
for (j = length - k - 1; j > 0; j--)
if (g[j] != 0)
bb[j] = bb[j - 1] ^ feedback;
else
bb[j] = bb[j - 1];
bb[0] = g[0] && feedback;
} else {
for (j = length - k - 1; j > 0; j--)
bb[j] = bb[j - 1];
bb[0] = 0;
}
}
}
void
decode_bch()
/*
* Simon Rockliff's implementation of Berlekamp's algorithm.
*
* Assume we have received bits in recd[i], i=0..(n-1).
*
* Compute the 2*t syndromes by substituting alpha^i into rec(X) and
* evaluating, storing the syndromes in s[i], i=1..2t (leave s[0] zero) .
* Then we use the Berlekamp algorithm to find the error location polynomial
* elp[i].
*
* If the degree of the elp is >t, then we cannot correct all the errors, and
* we have detected an uncorrectable error pattern. We output the information
* bits uncorrected.
*
* If the degree of elp is <=t, we substitute alpha^i , i=1..n into the elp
* to get the roots, hence the inverse roots, the error location numbers.
* This step is usually called "Chien's search".
*
* If the number of errors located is not equal the degree of the elp, then
* the decoder assumes that there are more than t errors and cannot correct
* them, only detect them. We output the information bits uncorrected.
*/
{
register int i, j, u, q, t2, count = 0, syn_error = 0;
int elp[1026][1024], d[1026], l[1026], u_lu[1026], s[1025];
int root[200], loc[200], reg[201];
(void)(root);
t2 = 2 * t;
/* first form the syndromes */
for (i = 1; i <= t2; i++) {
s[i] = 0;
for (j = 0; j < length; j++)
if (recd[j] != 0)
s[i] ^= alpha_to[(i * j) % n];
if (s[i] != 0)
syn_error = 1; /* set error flag if non-zero syndrome */
/*
* Note: If the code is used only for ERROR DETECTION, then
* exit program here indicating the presence of errors.
*/
/* convert syndrome from polynomial form to index form */
s[i] = index_of[s[i]];
}
if (syn_error) { /* if there are errors, try to correct them */
/*
* Compute the error location polynomial via the Berlekamp
* iterative algorithm. Following the terminology of Lin and
* Costello's book : d[u] is the 'mu'th discrepancy, where
* u='mu'+1 and 'mu' (the Greek letter!) is the step number
* ranging from -1 to 2*t (see L&C), l[u] is the degree of
* the elp at that step, and u_l[u] is the difference between
* the step number and the degree of the elp.
*/
/* initialise table entries */
d[0] = 0; /* index form */
d[1] = s[1]; /* index form */
elp[0][0] = 0; /* index form */
elp[1][0] = 1; /* polynomial form */
for (i = 1; i < t2; i++) {
elp[0][i] = -1; /* index form */
elp[1][i] = 0; /* polynomial form */
}
l[0] = 0;
l[1] = 0;
u_lu[0] = -1;
u_lu[1] = 0;
u = 0;
do {
u++;
if (d[u] == -1) {
l[u + 1] = l[u];
for (i = 0; i <= l[u]; i++) {
elp[u + 1][i] = elp[u][i];
elp[u][i] = index_of[elp[u][i]];
}
} else
/*
* search for words with greatest u_lu[q] for
* which d[q]!=0
*/
{
q = u - 1;
while ((d[q] == -1) && (q > 0))
q--;
/* have found first non-zero d[q] */
if (q > 0) {
j = q;
do {
j--;
if ((d[j] != -1) && (u_lu[q] < u_lu[j]))
q = j;
} while (j > 0);
}
/*
* have now found q such that d[u]!=0 and
* u_lu[q] is maximum
*/
/* store degree of new elp polynomial */
if (l[u] > l[q] + u - q)
l[u + 1] = l[u];
else
l[u + 1] = l[q] + u - q;
/* form new elp(x) */
for (i = 0; i < t2; i++)
elp[u + 1][i] = 0;
for (i = 0; i <= l[q]; i++)
if (elp[q][i] != -1)
elp[u + 1][i + u - q] =
alpha_to[(d[u] + n - d[q] + elp[q][i]) % n];
for (i = 0; i <= l[u]; i++) {
elp[u + 1][i] ^= elp[u][i];
elp[u][i] = index_of[elp[u][i]];
}
}
u_lu[u + 1] = u - l[u + 1];
/* form (u+1)th discrepancy */
if (u < t2) {
/* no discrepancy computed on last iteration */
if (s[u + 1] != -1)
d[u + 1] = alpha_to[s[u + 1]];
else
d[u + 1] = 0;
for (i = 1; i <= l[u + 1]; i++)
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
d[u + 1] ^= alpha_to[(s[u + 1 - i]
+ index_of[elp[u + 1][i]]) % n];
/* put d[u+1] into index form */
d[u + 1] = index_of[d[u + 1]];
}
} while ((u < t2) && (l[u + 1] <= t));
u++;
if (l[u] <= t) {/* Can correct errors */
/* put elp into index form */
for (i = 0; i <= l[u]; i++)
elp[u][i] = index_of[elp[u][i]];
for (i = 0; i <= l[u]; i++)
/* Chien search: find roots of the error location polynomial */
for (i = 1; i <= l[u]; i++)
reg[i] = elp[u][i];
count = 0;
for (i = 1; i <= n; i++) {
q = 1;
for (j = 1; j <= l[u]; j++)
if (reg[j] != -1) {
reg[j] = (reg[j] + j) % n;
q ^= alpha_to[reg[j]];
}
if (!q) { /* store root and error
* location number indices */
root[count] = i;
loc[count] = n - i;
count++;
}
}
if (count == l[u])
/* no. roots = degree of elp hence <= t errors */
for (i = 0; i < l[u]; i++)
recd[loc[i]] ^= 1;
}
}
}
//bugfix on 32-bit cygwin, probably overflowed here
unsigned long long int messagepp = 0x0;
//very simplified version, just to encode, get frame and compare
unsigned long long int edacs_bch (unsigned long long int message)
{
int i;
//not ideal to run these every frame, will want to eventually run once on start of DSD-FME, and store values
read_p(); /* Read m */
generate_gf(); /* Construct the Galois Field GF(2**m) */
gen_poly(); /* Compute the generator polynomial of BCH code */
//test shows this works, but output from program is that the poly is backwards, not sure if it corrects okay though
for (i = 0; i < k; i++){
ddata[i] = ( (message >> i) & 0x1 ); //loaded up backwards? or just outputs backwards?
}
encode_bch(); /* encode data */
/*
* recd[] are the coefficients of c(x) = x**(length-k)*data(x) + b(x)
*/
for (i = 0; i < length - k; i++)
recd[i] = bb[i];
for (i = 0; i < k; i++)
recd[i + length - k] = ddata[i];
for (i = 0; i < length; i++) {
messagepp = (messagepp << 1) | recd[39-i]; //get it in the correct direction
}
return (messagepp);
}

2209
src/edacs-fme.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -178,146 +178,167 @@ int ez_rs28_sacch (int payload[180], int parity[132])
return (ec); return (ec);
} }
//I-ISCH Lookup section, borrowed from OP25 //std::map <std::uint64_t, int> isch_map;
std::map <std::string, int> isch_map; std::map <uint64_t, int> isch_map; //User Noted GCC potential compiler error fix on BB OP25
void map_isch() void map_isch()
{ {
isch_map["184229d461"] = 0; isch_map[0x184229d461ULL] = 0;
isch_map["18761451f6"] = 1; isch_map[0x18761451f6ULL] = 1;
isch_map["181ae27e2f"] = 2; isch_map[0x181ae27e2fULL] = 2;
isch_map["182edffbb8"] = 3; isch_map[0x182edffbb8ULL] = 3;
isch_map["18df8a7510"] = 4; isch_map[0x18df8a7510ULL] = 4;
isch_map["18ebb7f087"] = 5; isch_map[0x18ebb7f087ULL] = 5;
isch_map["188741df5e"] = 6; isch_map[0x188741df5eULL] = 6;
isch_map["18b37c5ac9"] = 7; isch_map[0x18b37c5ac9ULL] = 7;
isch_map["1146a44f13"] = 8; isch_map[0x1146a44f13ULL] = 8;
isch_map["117299ca84"] = 9; isch_map[0x117299ca84ULL] = 9;
isch_map["111e6fe55d"] = 10; isch_map[0x111e6fe55dULL] = 10;
isch_map["112a5260ca"] = 11; isch_map[0x112a5260caULL] = 11;
isch_map["11db07ee62"] = 12; isch_map[0x11db07ee62ULL] = 12;
isch_map["11ef3a6bf5"] = 13; isch_map[0x11ef3a6bf5ULL] = 13;
isch_map["1183cc442c"] = 14; isch_map[0x1183cc442cULL] = 14;
isch_map["11b7f1c1bb"] = 15; isch_map[0x11b7f1c1bbULL] = 15;
isch_map["1a4a2e239e"] = 16; isch_map[0x1a4a2e239eULL] = 16;
isch_map["1a7e13a609"] = 17; isch_map[0x1a7e13a609ULL] = 17;
isch_map["1a12e589d0"] = 18; isch_map[0x1a12e589d0ULL] = 18;
isch_map["1a26d80c47"] = 19; isch_map[0x1a26d80c47ULL] = 19;
isch_map["1ad78d82ef"] = 20; isch_map[0x1ad78d82efULL] = 20;
isch_map["1ae3b00778"] = 21; isch_map[0x1ae3b00778ULL] = 21;
isch_map["1a8f4628a1"] = 22; isch_map[0x1a8f4628a1ULL] = 22;
isch_map["1abb7bad36"] = 23; isch_map[0x1abb7bad36ULL] = 23;
isch_map["134ea3b8ec"] = 24; isch_map[0x134ea3b8ecULL] = 24;
isch_map["137a9e3d7b"] = 25; isch_map[0x137a9e3d7bULL] = 25;
isch_map["13166812a2"] = 26; isch_map[0x13166812a2ULL] = 26;
isch_map["1322559735"] = 27; isch_map[0x1322559735ULL] = 27;
isch_map["13d300199d"] = 28; isch_map[0x13d300199dULL] = 28;
isch_map["13e73d9c0a"] = 29; isch_map[0x13e73d9c0aULL] = 29;
isch_map["138bcbb3d3"] = 30; isch_map[0x138bcbb3d3ULL] = 30;
isch_map["13bff63644"] = 31; isch_map[0x13bff63644ULL] = 31;
isch_map["1442f705ef"] = 32; isch_map[0x1442f705efULL] = 32;
isch_map["1476ca8078"] = 33; isch_map[0x1476ca8078ULL] = 33;
isch_map["141a3cafa1"] = 34; isch_map[0x141a3cafa1ULL] = 34;
isch_map["142e012a36"] = 35; isch_map[0x142e012a36ULL] = 35;
isch_map["14df54a49e"] = 36; isch_map[0x14df54a49eULL] = 36;
isch_map["14eb692109"] = 37; isch_map[0x14eb692109ULL] = 37;
isch_map["14879f0ed0"] = 38; isch_map[0x14879f0ed0ULL] = 38;
isch_map["14b3a28b47"] = 39; isch_map[0x14b3a28b47ULL] = 39;
isch_map["1d467a9e9d"] = 40; isch_map[0x1d467a9e9dULL] = 40;
isch_map["1d72471b0a"] = 41; isch_map[0x1d72471b0aULL] = 41;
isch_map["1d1eb134d3"] = 42; isch_map[0x1d1eb134d3ULL] = 42;
isch_map["1d2a8cb144"] = 43; isch_map[0x1d2a8cb144ULL] = 43;
isch_map["1ddbd93fec"] = 44; isch_map[0x1ddbd93fecULL] = 44;
isch_map["1defe4ba7b"] = 45; isch_map[0x1defe4ba7bULL] = 45;
isch_map["1d831295a2"] = 46; isch_map[0x1d831295a2ULL] = 46;
isch_map["1db72f1035"] = 47; isch_map[0x1db72f1035ULL] = 47;
isch_map["164af0f210"] = 48; isch_map[0x164af0f210ULL] = 48;
isch_map["167ecd7787"] = 49; isch_map[0x167ecd7787ULL] = 49;
isch_map["16123b585e"] = 50; isch_map[0x16123b585eULL] = 50;
isch_map["162606ddc9"] = 51; isch_map[0x162606ddc9ULL] = 51;
isch_map["16d7535361"] = 52; isch_map[0x16d7535361ULL] = 52;
isch_map["16e36ed6f6"] = 53; isch_map[0x16e36ed6f6ULL] = 53;
isch_map["168f98f92f"] = 54; isch_map[0x168f98f92fULL] = 54;
isch_map["16bba57cb8"] = 55; isch_map[0x16bba57cb8ULL] = 55;
isch_map["1f4e7d6962"] = 56; isch_map[0x1f4e7d6962ULL] = 56;
isch_map["1f7a40ecf5"] = 57; isch_map[0x1f7a40ecf5ULL] = 57;
isch_map["1f16b6c32c"] = 58; isch_map[0x1f16b6c32cULL] = 58;
isch_map["1f228b46bb"] = 59; isch_map[0x1f228b46bbULL] = 59;
isch_map["1fd3dec813"] = 60; isch_map[0x1fd3dec813ULL] = 60;
isch_map["1fe7e34d84"] = 61; isch_map[0x1fe7e34d84ULL] = 61;
isch_map["1f8b15625d"] = 62; isch_map[0x1f8b15625dULL] = 62;
isch_map["1fbf28e7ca"] = 63; isch_map[0x1fbf28e7caULL] = 63;
isch_map["84d62c339"] = 64; isch_map[0x084d62c339ULL] = 64;
isch_map["8795f46ae"] = 65; isch_map[0x08795f46aeULL] = 65;
isch_map["815a96977"] = 66; isch_map[0x0815a96977ULL] = 66;
isch_map["82194ece0"] = 67; isch_map[0x082194ece0ULL] = 67;
isch_map["8d0c16248"] = 68; isch_map[0x08d0c16248ULL] = 68;
isch_map["8e4fce7df"] = 69; isch_map[0x08e4fce7dfULL] = 69;
isch_map["8880ac806"] = 70; isch_map[0x08880ac806ULL] = 70;
isch_map["8bc374d91"] = 71; isch_map[0x08bc374d91ULL] = 71;
isch_map["149ef584b"] = 72; isch_map[0x0149ef584bULL] = 72;
isch_map["17dd2dddc"] = 73; isch_map[0x017dd2dddcULL] = 73;
isch_map["11124f205"] = 74; isch_map[0x011124f205ULL] = 74;
isch_map["125197792"] = 75; isch_map[0x0125197792ULL] = 75;
isch_map["1d44cf93a"] = 76; isch_map[0x01d44cf93aULL] = 76;
isch_map["1e0717cad"] = 77; isch_map[0x01e0717cadULL] = 77;
isch_map["18c875374"] = 78; isch_map[0x018c875374ULL] = 78;
isch_map["1b8bad6e3"] = 79; isch_map[0x01b8bad6e3ULL] = 79;
isch_map["a456534c6"] = 80; isch_map[0x0a456534c6ULL] = 80;
isch_map["a7158b151"] = 81; isch_map[0x0a7158b151ULL] = 81;
isch_map["a1dae9e88"] = 82; isch_map[0x0a1dae9e88ULL] = 82;
isch_map["a29931b1f"] = 83; isch_map[0x0a29931b1fULL] = 83;
isch_map["ad8c695b7"] = 84; isch_map[0x0ad8c695b7ULL] = 84;
isch_map["aecfb1020"] = 85; isch_map[0x0aecfb1020ULL] = 85;
isch_map["a800d3ff9"] = 86; isch_map[0x0a800d3ff9ULL] = 86;
isch_map["ab430ba6e"] = 87; isch_map[0x0ab430ba6eULL] = 87;
isch_map["341e8afb4"] = 88; isch_map[0x0341e8afb4ULL] = 88;
isch_map["375d52a23"] = 89; isch_map[0x0375d52a23ULL] = 89;
isch_map["3192305fa"] = 90; isch_map[0x03192305faULL] = 90;
isch_map["32d1e806d"] = 91; isch_map[0x032d1e806dULL] = 91;
isch_map["3dc4b0ec5"] = 92; isch_map[0x03dc4b0ec5ULL] = 92;
isch_map["3e8768b52"] = 93; isch_map[0x03e8768b52ULL] = 93;
isch_map["38480a48b"] = 94; isch_map[0x038480a48bULL] = 94;
isch_map["3b0bd211c"] = 95; isch_map[0x03b0bd211cULL] = 95;
isch_map["44dbc12b7"] = 96; isch_map[0x044dbc12b7ULL] = 96;
isch_map["479819720"] = 97; isch_map[0x0479819720ULL] = 97;
isch_map["41577b8f9"] = 98; isch_map[0x041577b8f9ULL] = 98;
isch_map["4214a3d6e"] = 99; isch_map[0x04214a3d6eULL] = 99;
isch_map["4d01fb3c6"] = 100; isch_map[0x04d01fb3c6ULL] = 100;
isch_map["4e4223651"] = 101; isch_map[0x04e4223651ULL] = 101;
isch_map["488d41988"] = 102; isch_map[0x0488d41988ULL] = 102;
isch_map["4bce99c1f"] = 103; isch_map[0x04bce99c1fULL] = 103;
isch_map["d493189c5"] = 104; isch_map[0x0d493189c5ULL] = 104;
isch_map["d7d0c0c52"] = 105; isch_map[0x0d7d0c0c52ULL] = 105;
isch_map["d11fa238b"] = 106; isch_map[0x0d11fa238bULL] = 106;
isch_map["d25c7a61c"] = 107; isch_map[0x0d25c7a61cULL] = 107;
isch_map["dd49228b4"] = 108; isch_map[0x0dd49228b4ULL] = 108;
isch_map["de0afad23"] = 109; isch_map[0x0de0afad23ULL] = 109;
isch_map["d8c5982fa"] = 110; isch_map[0x0d8c5982faULL] = 110;
isch_map["db864076d"] = 111; isch_map[0x0db864076dULL] = 111;
isch_map["645bbe548"] = 112; isch_map[0x0645bbe548ULL] = 112;
isch_map["6718660df"] = 113; isch_map[0x06718660dfULL] = 113;
isch_map["61d704f06"] = 114; isch_map[0x061d704f06ULL] = 114;
isch_map["6294dca91"] = 115; isch_map[0x06294dca91ULL] = 115;
isch_map["6d8184439"] = 116; isch_map[0x06d8184439ULL] = 116;
isch_map["6ec25c1ae"] = 117; isch_map[0x06ec25c1aeULL] = 117;
isch_map["680d3ee77"] = 118; isch_map[0x0680d3ee77ULL] = 118;
isch_map["6b4ee6be0"] = 119; isch_map[0x06b4ee6be0ULL] = 119;
isch_map["f41367e3a"] = 120; isch_map[0x0f41367e3aULL] = 120;
isch_map["f750bfbad"] = 121; isch_map[0x0f750bfbadULL] = 121;
isch_map["f19fdd474"] = 122; isch_map[0x0f19fdd474ULL] = 122;
isch_map["f2dc051e3"] = 123; isch_map[0x0f2dc051e3ULL] = 123;
isch_map["fdc95df4b"] = 124; isch_map[0x0fdc95df4bULL] = 124;
isch_map["fe8a85adc"] = 125; isch_map[0x0fe8a85adcULL] = 125;
isch_map["f845e7505"] = 126; isch_map[0x0f845e7505ULL] = 126;
isch_map["fb063f092"] = 127; isch_map[0x0fb063f092ULL] = 127;
isch_map[0x575d57f7ffULL] = -2; // S-ISCH
} }
unsigned long long int isch_lookup (unsigned long long int isch) //I-ISCH Lookup, borrowed from OP25 (now w/ error correction)
int isch_lookup (uint64_t isch)
{ {
map_isch(); //initialize the lookup map map_isch(); //initialize the lookup map
char s[64]; int decoded = -2;
unsigned long long int decoded = -2; //initialize lookup to an invalid number
sprintf(s, "%llx", isch); // Must contain bit errors if no exact match, so
decoded = isch_map[s]; // look for codeword with smallest hamming distance
return(decoded); if (isch_map.find(isch) == isch_map.end())
} {
int popct, popmin = 40;
for (auto it = isch_map.begin(); it != isch_map.end(); ++it)
{
popct = __builtin_popcountll(isch ^ it->first);
// Encoding is (40, 9, 16) which can correct at most 7 bit-errors
if ((popct <= 7) && (popct < popmin))
{
decoded = it->second;
popmin = popct;
}
}
return decoded;
}
else // No errors, so simply return the matching value
decoded = isch_map[isch];
return decoded;
}

115
src/fec.c
View File

@@ -760,6 +760,82 @@ bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, i
// ======================================================================================== // ========================================================================================
void rand_test_20_8() //from dforsi as a pull request to DSDcc
{
unsigned char msg[8];
unsigned char codeword[20], xcodeword[20];
int idx1, idx2, idx3 = 0;
int dataIn, dataOut; UNUSED(dataIn); //don't know why its reporting dataIn as unused for
int passCount = 0, failCount = 0, parityFailCount = 0;
// Run multiple times, to randomly corrupt different bits
// Takes about 10 seconds on a fast PC
for (int repeat = 0; repeat < 100000/2; repeat++)
{
// Exhaustively test all 8-bit inputs
for (int dataIn = 0; dataIn < 256; dataIn++)
{
// Convert to array of bits
for (int j = 0; j < 8; j++) {
msg[j] = (dataIn >> j) & 1;
}
// Encode
Golay_20_8_encode(msg, codeword);
// Save copy of uncorrupted codeword
memcpy(xcodeword, codeword, 20*sizeof(unsigned char));
//change the seed each time, using time(NULL) will only change the seed once every second, otherwise resets it to the same seed
srand(dataIn+dataOut);
// Randomly corrupt up to 3 bits
idx1 = rand() % 20;
idx2 = rand() % 20;
idx3 = rand() % 20;
codeword[idx1] ^= codeword[idx1];
codeword[idx2] ^= codeword[idx2];
codeword[idx3] ^= codeword[idx3];
//flip the parity bit
// codeword[19] ^= 1;
bool fail = false;
// Decode and correct errors
dataOut = 0;
if (Golay_20_8_decode(codeword))
{
// Check data is corrected
for (int j = 0; j < 8; j++) {
dataOut |= codeword[j] << j;
}
if (dataIn != dataOut) {
fail = true;
}
// Check also that parity has been corrected, as we previously had a bug with this
if (memcmp(codeword, xcodeword, 20)) {
parityFailCount++;
}
}
else
{
fail = true;
}
if (fail)
{
fprintf (stderr, "\n Decode Failed: IN:%05X; OUT:%05X; IDX: %d, %d, %d; ", dataIn, dataOut, idx1, idx2, idx3);
failCount++;
}
else
{
passCount++;
// fprintf (stderr, "\n Decode Passed: IN:%05X; OUT:%05X; IDX: %d, %d, %d; ", dataIn, dataOut, idx1, idx2, idx3);
}
}
}
fprintf (stderr, "\n Passcount: %d; Failcount: %d; Parity Fail Count: %d \n", passCount, failCount, parityFailCount);
}
void Golay_20_8_init() void Golay_20_8_init()
{ {
@@ -806,7 +882,7 @@ void Golay_20_8_init()
syndromeIP = syndromeI ^ (1 << (11-ip)); syndromeIP = syndromeI ^ (1 << (11-ip));
Golay_20_8_m_corr[syndromeIP][0] = i1; Golay_20_8_m_corr[syndromeIP][0] = i1;
Golay_20_8_m_corr[syndromeIP][1] = i2; Golay_20_8_m_corr[syndromeIP][1] = i2;
Golay_20_8_m_corr[syndromeIP][2] = 12 + ip; Golay_20_8_m_corr[syndromeIP][2] = 8 + ip;
} }
} }
@@ -824,14 +900,14 @@ void Golay_20_8_init()
{ {
syndromeIP1 = syndromeI ^ (1 << (11-ip1)); syndromeIP1 = syndromeI ^ (1 << (11-ip1));
Golay_20_8_m_corr[syndromeIP1][0] = i1; Golay_20_8_m_corr[syndromeIP1][0] = i1;
Golay_20_8_m_corr[syndromeIP1][1] = 12 + ip1; Golay_20_8_m_corr[syndromeIP1][1] = 8 + ip1;
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
{ {
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2)); syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
Golay_20_8_m_corr[syndromeIP2][0] = i1; Golay_20_8_m_corr[syndromeIP2][0] = i1;
Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip1; Golay_20_8_m_corr[syndromeIP2][1] = 8 + ip1;
Golay_20_8_m_corr[syndromeIP2][2] = 12 + ip2; Golay_20_8_m_corr[syndromeIP2][2] = 8 + ip2;
} }
} }
} }
@@ -840,23 +916,25 @@ void Golay_20_8_init()
for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
{ {
syndromeIP1 = (1 << (11-ip1)); syndromeIP1 = (1 << (11-ip1));
Golay_20_8_m_corr[syndromeIP1][0] = 12 + ip1; Golay_20_8_m_corr[syndromeIP1][0] = 8 + ip1;
for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
{ {
syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2)); syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
Golay_20_8_m_corr[syndromeIP2][0] = 12 + ip1; Golay_20_8_m_corr[syndromeIP2][0] = 8 + ip1;
Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip2; Golay_20_8_m_corr[syndromeIP2][1] = 8 + ip2;
for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
{ {
syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3)); syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
Golay_20_8_m_corr[syndromeIP3][0] = 12 + ip1; Golay_20_8_m_corr[syndromeIP3][0] = 8 + ip1;
Golay_20_8_m_corr[syndromeIP3][1] = 12 + ip2; Golay_20_8_m_corr[syndromeIP3][1] = 8 + ip2;
Golay_20_8_m_corr[syndromeIP3][2] = 12 + ip3; Golay_20_8_m_corr[syndromeIP3][2] = 8 + ip3;
} }
} }
} }
// rand_test_20_8(); //test
} }
// Not very efficient but encode is used for unit testing only // Not very efficient but encode is used for unit testing only
@@ -1230,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) void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
{ {
int i = 0, j = 0; int i = 0, j = 0;
memset(encodedBits, 0, 24); // memset(encodedBits, 0, 24);
for (i = 0; i < 12; i++) for (i = 0; i < 12; i++)
{ {
@@ -1248,7 +1326,7 @@ void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
for (i = 0; i < 24; i++) for (i = 0; i < 24; i++)
{ {
encodedBits[i] %= 2; encodedBits[i] %= 2;
// fprintf (stderr, "%b", encodedBits[i]); //disable later on // fprintf (stderr, "%b", encodedBits[i]); //disable later on
} }
} }
@@ -1397,10 +1475,11 @@ void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits)
bool QR_16_7_6_decode(unsigned char *rxBits) bool QR_16_7_6_decode(unsigned char *rxBits)
{ {
//2 bit errors or less
unsigned int syndromeI = 0; // syndrome index unsigned int syndromeI = 0; // syndrome index
int is = 0; int is = 0;
int i = 0; int i = 0;
int corrections = 0;
for (is = 0; is < 9; is++) for (is = 0; is < 9; is++)
{ {
syndromeI += (((rxBits[0] * QR_16_7_6_m_H[16*is + 0]) syndromeI += (((rxBits[0] * QR_16_7_6_m_H[16*is + 0])
@@ -1434,6 +1513,7 @@ bool QR_16_7_6_decode(unsigned char *rxBits)
else else
{ {
rxBits[QR_16_7_6_m_corr[syndromeI][i]] ^= 1; // flip bit rxBits[QR_16_7_6_m_corr[syndromeI][i]] ^= 1; // flip bit
corrections++;
} }
} }
@@ -1441,8 +1521,15 @@ bool QR_16_7_6_decode(unsigned char *rxBits)
{ {
return false; return false;
} }
} }
//disabling again for now
// if (corrections > 1) //no more than 1-bit error, else consider failure?
// {
// return false;
// }
return true; return true;
} }

3833
src/m17.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,124 +0,0 @@
#include "dsd.h"
#include "nxdn96_const.h"
void
processNXDN96 (dsd_opts * opts, dsd_state * state)
{
int i, j, k, dibit;
char ambe_fr[4][24];
const int *w, *x, *y, *z;
if (opts->errorbars == 1)
{
fprintf (stderr, "VOICE e:");
}
#ifdef NXDN_DUMP
fprintf (stderr, "\n");
#endif
for (k = 0; k < 4; k++)
{
for (i = 0; i < 222; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf (stderr, "%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
fprintf (stderr, " ");
#endif
if (k < 3)
{
for (j = 0; j < 4; j++)
{
w = nW;
x = nX;
y = nY;
z = nZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf (stderr, "%c", dibit + 48);
#endif
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
#ifdef NXDN_DUMP
fprintf (stderr, " ");
#endif
}
}
else
{
for (j = 0; j < 3; j++) // we skip the last voice frame until frame sync can work with < 24 symbols
{
w = nW;
x = nX;
y = nY;
z = nZ;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf (stderr, "%c", dibit + 48);
#endif
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
w++;
x++;
y++;
z++;
}
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
#ifdef NXDN_DUMP
fprintf (stderr, " ");
#endif
}
}
if (k < 3)
{
for (i = 0; i < 18; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf (stderr, "%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
fprintf (stderr, " ");
#endif
}
else
{
for (i = 0; i < 30; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf (stderr, "%c", dibit + 48);
#endif
}
}
}
#ifdef NXDN_DUMP
fprintf (stderr, "\n");
#endif
if (opts->errorbars == 1)
{
printf ("\n");
}
}

View File

@@ -24,10 +24,8 @@
/* Include ------------------------------------------------------------------*/ /* Include ------------------------------------------------------------------*/
//#include "nxdnconvolution.h"
#include <stdio.h> #include <stdio.h>
//#include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
@@ -38,40 +36,28 @@
/* Global variables ---------------------------------------------------------*/ /* Global variables ---------------------------------------------------------*/
static const uint8_t CNXDNConvolution_BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; static const uint8_t CNXDNConvolution_BIT_MASK_TABLE[8] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | CNXDNConvolution_BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~CNXDNConvolution_BIT_MASK_TABLE[(i)&7]) #define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | CNXDNConvolution_BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~CNXDNConvolution_BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & CNXDNConvolution_BIT_MASK_TABLE[(i)&7]) #define READ_BIT1(p,i) (p[(i)>>3] & CNXDNConvolution_BIT_MASK_TABLE[(i)&7])
static const uint8_t CNXDNConvolution_BRANCH_TABLE1[] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U}; static const uint8_t CNXDNConvolution_BRANCH_TABLE1[8] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
static const uint8_t CNXDNConvolution_BRANCH_TABLE2[] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U}; static const uint8_t CNXDNConvolution_BRANCH_TABLE2[8] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U};
static const unsigned int CNXDNConvolution_NUM_OF_STATES_D2 = 8U; static const unsigned int CNXDNConvolution_NUM_OF_STATES_D2 = 8U;
static const unsigned int CNXDNConvolution_NUM_OF_STATES = 16U;
static const uint32_t CNXDNConvolution_M = 4U; static const uint32_t CNXDNConvolution_M = 4U;
static const unsigned int CNXDNConvolution_K = 5U; static const unsigned int CNXDNConvolution_K = 5U;
static uint16_t m_metrics1[16U] = {0}; //NOTE:
static uint16_t m_metrics2[16U] = {0}; uint16_t m_metrics1[16];
static uint64_t m_decisions[300U] = {0}; uint16_t m_metrics2[16];
static uint16_t * m_oldMetrics = NULL; uint64_t m_decisions[8*300];
static uint16_t * m_newMetrics = NULL; uint16_t * m_oldMetrics = NULL;
static uint64_t * m_dp = NULL; uint16_t * m_newMetrics = NULL;
uint64_t * m_dp = NULL;
/* Functions ----------------------------------------------------------------*/ /* Functions ----------------------------------------------------------------*/
void CNXDNConvolution_start(void)
{
memset(m_metrics1, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
memset(m_metrics2, 0x00U, CNXDNConvolution_NUM_OF_STATES * sizeof(uint16_t));
m_oldMetrics = m_metrics1;
m_newMetrics = m_metrics2;
m_dp = m_decisions;
}
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1) void CNXDNConvolution_decode(uint8_t s0, uint8_t s1)
{ {
uint8_t i = 0; uint8_t i = 0;
@@ -169,3 +155,19 @@ void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsign
} }
} }
void CNXDNConvolution_start(void)
{
m_oldMetrics = m_metrics1;
m_newMetrics = m_metrics2;
m_dp = m_decisions;
}
void CNXDNConvolution_init()
{
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

@@ -1,127 +0,0 @@
#include "dsd.h"
#include "nxdn_const.h"
void processNXDNData (dsd_opts * opts, dsd_state * state)
{
int i, dibit = 0;
unsigned char sacch_raw[72] = {0};
unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */
unsigned char *pr;
uint8_t CrcIsGood = 0;
uint8_t StructureField = 0;
uint8_t RAN = 0;
uint8_t PartOfFrame = 0;
/* Remove compiler warning */
//UNUSED_VARIABLE(dibit);
//if using NXDN Scrambling, run LFSRN (dummy ambe values) to continue seed
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
{
char ambe_temp[49] = {0};
char ambe_d[49] = {0};
for (i = 0; i < 4; i++)
{
LFSRN(ambe_temp, ambe_d, state);
}
}
if (opts->errorbars == 1)
{
fprintf(stderr, "DATA - ");
}
/* Start pseudo-random NXDN sequence after
* LICH = 16 bit = 8 dibit
* ==> Index 8 */
pr = (unsigned char *)(&nxdnpr2[8]);
for (i = 0; i < 30; i++)
{
dibit = getDibit (opts, state);
/* Store and de-interleave directly SACCH bits */
sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1
sacch_raw[(2*i)+1] = (1 & dibit); // bit 0
pr++;
#ifdef NXDN_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
}
#ifdef NXDN_DUMP
fprintf(stderr, " ");
#endif
/* Decode the SACCH fields */
CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded);
StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */
RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */
/* Compute the Part of Frame according to the structure field */
if (StructureField == 3) PartOfFrame = 0;
else if(StructureField == 2) PartOfFrame = 1;
else if(StructureField == 1) PartOfFrame = 2;
else if(StructureField == 0) PartOfFrame = 3;
else PartOfFrame = 0; /* Normally we should never go here */
/* Fill the SACCH structure */
state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood;
state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField;
state->NxdnSacchRawPart[PartOfFrame].RAN = RAN;
memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */
//fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
if(CrcIsGood)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1);
fprintf (stderr, "%s", KNRM);
//fprintf (stderr, "(CRC OK) ");
state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead
}
else
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, "(CRC ERR) ");
fprintf (stderr, "%s", KNRM);
}
/* Decode the SACCH only when all 4 voice frame
* SACCH spare parts have been received */
if(PartOfFrame == 3)
{
/* Decode the entire SACCH content */
NXDN_SACCH_Full_decode(opts, state);
}
for (i = 0; i < 144; i++)
{
dibit = getDibit (opts, state);
#ifdef NXDN_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
}
if (opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
/* Reset the SACCH CRCs when all 4 voice frame
* SACCH spare parts have been received */
if(PartOfFrame == 3)
{
/* Reset all CRCs of the SACCH */
for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0;
//reset Scrambler seed
if (state->nxdn_cipher_type == 0x1)
{
state->payload_miN = 0;
}
}
} /* End processNXDNData() */

1332
src/nxdn_deperm.c Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More