191 Commits

Author SHA1 Message Date
lwvmobile
8d522e25c4 Fix Compiler Error on RTL Dev Enum; 2023-09-13 13:24:11 -04:00
lwvmobile
b1013c15ad Add RTL Device Enum and SN support to Ncurses; 2023-09-13 11:13:46 -04:00
lwvmobile
23d8d0cc77 Add RTL Device Enum and SN support to CLI; 2023-09-13 11:12:08 -04:00
lwvmobile
6e60a4e7d1 Fix Keyring Loader to allow KeyID of 0 (P25); 2023-09-12 17:49:57 -04:00
lwvmobile
48a3d55231 Update Version for next Aero Build Date; 2023-09-12 17:43:25 -04:00
lwvmobile
aef12ff74d DMR - Tweak to CSBK (BTV_GRANT) and FLC (BTV); 2023-09-12 17:41:38 -04:00
lwvmobile
2353601719 DMR - Add T3 Multi Item Data Call Grants; Tweaks; 2023-09-12 17:40:59 -04:00
lwvmobile
668f70c1ba DMR T3 -- Add P_MAINT Decode; 2023-09-12 17:40:10 -04:00
lwvmobile
ec292ae738 DMR C_AHOY and Special Address Identifiers; 2023-09-12 17:39:29 -04:00
lwvmobile
9e56356e27 Fix Line Break Issue on DMR SLC Err; 2023-09-12 17:37:18 -04:00
lwvmobile
3d2a68b4bb DMR T3 Tweak to TG and SRC Values when Tuning; 2023-09-12 17:36:36 -04:00
lwvmobile
443c53e2ba Tweak DMR T3 Channel Numbering Information; 2023-09-08 19:53:36 -04:00
lwvmobile
6153f7bc4c Init Group Mode Str; Tweak Group List Conditions; 2023-09-07 12:04:14 -04:00
lwvmobile
4bbae54542 Fix EDACS AFS Reporting on PV Console Output; 2023-09-06 19:04:56 -04:00
lwvmobile
6e7f2962f0 Raw Signal Wav File Saving; #163 2023-09-05 11:28:50 -04:00
lwvmobile
d917f85926 EDACS Analog Call Dotting Sequence Detection; 2023-09-04 17:28:47 -04:00
lwvmobile
76d2866498 Fix/Tweak EDACS Dotting Sequence; 2023-09-04 17:26:48 -04:00
lwvmobile
2e098d52bc EDACS Dotting Sequence FS Detection and CC Jump; 2023-09-04 17:26:11 -04:00
lwvmobile
57629cefe4 Version/Date Update; 2023-08-27 15:06:32 -04:00
lwvmobile
fe3a135a92 Disable DMR MS/Simplex When Trunking Enabled; 2023-08-26 21:23:56 -04:00
lwvmobile
8d33c2b3d1 DMR SB TXI Tweaks; Add CRC4 Check to LE MI; 2023-08-26 17:28:06 -04:00
lwvmobile
593ffbbd66 DMR LE Minor Code Fix; Print Tweaks; 2023-08-26 09:32:40 -04:00
lwvmobile
592d57ad87 Fix M17 IV; 2023-08-25 09:16:34 -04:00
lwvmobile
9a31678d9a Fix M17 Enc Type Values; 2023-08-25 09:12:51 -04:00
lwvmobile
7b3a257df8 Fix EDACS Analog Call Preemption Conditions; 2023-08-22 09:21:03 -04:00
lwvmobile
55e792a925 Disable RTL RMS Function on ARM Devices (RPi); 2023-08-19 20:58:30 -04:00
lwvmobile
755f77f96c Temp Fix for EDACS Standard/Networked; 2023-08-19 12:45:22 -04:00
lwvmobile
1c17757a4e DMR 3/4 Simple Error Correction; 2023-08-19 07:43:30 -04:00
lwvmobile
abe2e61cf2 P25p2 I-ISCH/DUID Error Correction; 2023-08-17 13:44:22 -04:00
lwvmobile
c404825451 Analog Monitor Hold on SQL Break; Misc; 2023-08-13 11:43:04 -04:00
lwvmobile
769168da5b Prevent Possible Overflow in lbuf and lbuf2; 2023-08-11 14:59:50 -04:00
lwvmobile
14284c3cf1 More Cygwin M17 Related Bandaids; 2023-08-11 14:59:14 -04:00
lwvmobile
51f971b68d Update Install Notes and Include Arch Installer; 2023-08-11 12:52:28 -04:00
lwvmobile
02fdb7cd90 Fix Some NXDN Array Sizes and Chainbacks; 2023-08-11 12:21:22 -04:00
lwvmobile
64541a1958 M17 Misc Cleanup; 2023-08-11 12:20:47 -04:00
lwvmobile
0a675d3f0f Misc Code Cleanup; 2023-08-10 14:44:16 -04:00
lwvmobile
e79b6fd231 Simplify DMR Trellis Decoder; 2023-08-10 03:47:08 -04:00
lwvmobile
d356ed0dbc Add M17 CAN Value to Ncurses; Misc; 2023-08-09 20:54:07 -04:00
lwvmobile
495eb71090 Fixed Wrong Line; Fix the Correct Line This Time; 2023-08-09 04:10:03 -04:00
lwvmobile
6bf96f1df5 Forgot something; 2023-08-09 04:08:11 -04:00
lwvmobile
3a2db53c3b Fix RTL Source Audio Monitoring Bug; 2023-08-09 04:05:43 -04:00
lwvmobile
e038016c30 Fix Pulse Audio Output Source Monitor; 2023-08-09 02:16:12 -04:00
lwvmobile
7d6269efad WIP: Source Audio Monitoring on V2.1b; 2023-08-09 01:14:00 -04:00
lwvmobile
152f0ea7f6 EDACS Tweaks to Analog Call Handling; 2023-08-08 01:06:48 -04:00
lwvmobile
13443a25f3 Fix Annoying Alignment Issues; 2023-08-07 04:14:33 -04:00
lwvmobile
528f7294d9 Experimental EDACS Analog Voice Monitoring; 2023-08-07 03:48:39 -04:00
lwvmobile
83e3fa1061 Fix RTL RMS so it does't return Jank Values; 2023-08-07 03:43:39 -04:00
lwvmobile
9b3a2d96e3 Fix Some DateName Issues for dates in Aero; 2023-08-07 03:42:11 -04:00
lwvmobile
0829cdbdb0 Update Example_Usage for Icecast; #159 2023-08-07 03:38:15 -04:00
lwvmobile
9541aef382 Merge pull request #159 from francisuk1989/v2.1b-1
Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
2023-08-05 16:38:35 -04:00
lwvmobile
4caf6bb153 Update Example_Usage.md 2023-08-05 16:37:00 -04:00
Francis
dd77273218 Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
For them who wont to send audio to a icecast 2 server via WIndows.
2023-08-05 20:38:15 +01:00
lwvmobile
3bd3edb36f Fix Cygwin/Aero/OSS/M17 Junk; 2023-07-26 18:43:52 -04:00
lwvmobile
6f1cf0a279 Version/Tag Update 2.1b 2023-07-11 19:02:56 -04:00
lwvmobile
5d045b89e4 Fix Random Warnings on #152 2023-07-10 19:19:49 -04:00
lwvmobile
a2c4679632 M17 More Work and Fixes; #152 2023-07-10 19:13:16 -04:00
lwvmobile
986ed27d7d NXDN LZ Tweak on RCCH Disc; #123 2023-07-10 19:02:54 -04:00
lwvmobile
bae6a1545e Fix OSS Input/Output on M17 8K Sample; #152 2023-07-08 23:58:43 -04:00
lwvmobile
5240f00441 M17 Dbuf Temp Bug Fix; Misc; #152 2023-07-08 06:40:36 -04:00
lwvmobile
f7511e0976 Fix Cmake for Codec2 in Cygwin; #152 2023-07-08 06:07:09 -04:00
lwvmobile
bc27344b04 Fix M17 3200bps Voice; Misc M17 Tweaks; #152 2023-07-07 02:15:08 -04:00
lwvmobile
db97eb82a1 M17 Support (Partially Working Now); 2023-07-06 21:04:28 -04:00
lwvmobile
3f1b8ff736 M17 Initial Support (Non-Working State); 2023-07-05 14:27:25 -04:00
lwvmobile
54b9017146 Misc Minor Fixes; 2023-07-05 14:03:22 -04:00
lwvmobile
8ccaf2d261 DMR LE ENC Identifiers Tweak; 2023-07-03 12:31:58 -04:00
lwvmobile
209770175d Fix ysf.c Unused Variables Warnings; 2023-07-01 22:56:15 -04:00
lwvmobile
602079e681 Fix Trellis.c Unused Variables Warnings; 2023-07-01 22:47:36 -04:00
lwvmobile
82267b9ec8 Fix NXDN de-scrambling bug; 2023-07-01 22:40:05 -04:00
lwvmobile
87bf997b6e Add YSF to default decoding class; #143 2023-07-01 18:44:14 -04:00
lwvmobile
0a43d3202d YSF Fix CM Variable; Line Break; #146 2023-07-01 17:32:42 -04:00
lwvmobile
ee04cef6f2 YSF Radio ID Mode; Element Tweaks; #143 2023-07-01 17:32:22 -04:00
lwvmobile
b6fdfe48c1 Fix Line #137 2023-07-01 17:32:12 -04:00
lwvmobile
7a4bd2833f Refine/Fix YSF FICH Element Decode #143 2023-07-01 17:31:42 -04:00
lwvmobile
432ad448ba Fix YSF Full Rate Voice #143 2023-07-01 17:31:27 -04:00
lwvmobile
61be710bb0 Fix Code Tab Alignment #143 2023-07-01 17:30:57 -04:00
lwvmobile
3be8aacf77 WIP: YSF Decoding; #143 2023-07-01 17:30:29 -04:00
lwvmobile
4feb21cf0a Fix Exitflag Variable #136 2023-07-01 17:28:13 -04:00
lwvmobile
7d8162ab99 DMR LE/CAP+/Misc Tweaks; 2023-07-01 17:21:43 -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
77 changed files with 12080 additions and 4612 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ build
examples
*.bin
*.ans
*.patch

View File

@@ -1,11 +1,51 @@
project(dsd-fme-lite)
cmake_minimum_required(VERSION 2.8.11)
#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)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
#Set curses to ncurses, and wide true for ascii
set(CURSES_NEED_NCURSES 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 -DTONES to change default location of the tones.wav files (lwvmobile precompiled 'Aero' releases only)
option(TN
"Build with tone wav files in the dsd-fme folder and not in /usr/share/" OFF)
if (TN)
add_definitions(-DTONES)
endif ()
include(git_revision)
git_describe(GIT_TAG)
@@ -14,7 +54,8 @@ find_package(MBE REQUIRED)
find_package(ITPP REQUIRED)
find_package(RTLSDR)
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})
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
@@ -26,6 +67,12 @@ if(RTLSDR_FOUND)
add_definitions(-DUSE_RTLSDR)
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 HEADERS include/*.h include/*.hpp)
@@ -38,24 +85,24 @@ list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
include_directories("${PROJECT_SOURCE_DIR}/include")
ADD_EXECUTABLE(dsd-fme-lite ${SRCS} ${HEADERS})
TARGET_LINK_LIBRARIES(dsd-fme-lite ${LIBS})
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
include(GNUInstallDirs)
install(TARGETS dsd-fme-lite DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
# man page
find_program(HELP2MAN_FOUND help2man)
if (HELP2MAN_FOUND)
add_custom_command(TARGET dsd-fme-lite POST_BUILD
add_custom_command(TARGET dsd-fme POST_BUILD
COMMAND help2man
ARGS -n "Digital Speech Decoder"
--version-string=${GIT_TAG}
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
--no-info
$<TARGET_FILE:dsd-fme-lite>
$<TARGET_FILE:dsd-fme>
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme-lite.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
endif()
# uninstall target

View File

@@ -1,6 +1,18 @@
## Notice
This branch is for modifications to make a Windows 32-bit binary to be precompiled, please DO NOT use this branch if you are a Linux User, or copy any contents out of here to modify your existing setup!
# Digital Speech Decoder - Florida Man Edition
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
[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, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thank you everybody.
![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/main/dsd-fme2.png)
![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/main/dsd-fme3.png)
## Information
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/main/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/main/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/main/examples/trunking.sh "trunking examples").
## License
Copyright (C) 2010 DSD Author

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,67 @@
#! /bin/bash
clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer For Arch Linux
echo This will install the required packages, clone, build, and install DSD-FME only.
echo This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.
echo
echo MBELib is considered a requirement on this build.
echo You must view this notice prior to continuing.
echo The Patent Notice can be found at the site below.
echo https://github.com/lwvmobile/mbelib#readme
echo Please confirm that you have viewed the patent notice by entering y below.
echo
echo y/N
read ANSWER
Y='y'
if [[ $Y == $ANSWER ]]; 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
echo Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal
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.a /usr/lib/libmbe.a
sudo cp /usr/local/lib/libmbe.so /usr/lib/libmbe.so #this is the only one we need to copy
#sudo cp /usr/local/lib/libmbe.so.1 /usr/lib/libmbe.so.1
#sudo cp /usr/local/lib/libmbe.so.1.3 /usr/lib/libmbe.so.1.3
cd ..
cd ..
git clone https://github.com/lwvmobile/dsd-fme
### For branch v2.1b - git clone --branch v2.1b https://github.com/lwvmobile/dsd-fme
cd dsd-fme
git checkout v2.1b
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
sudo rm -R dsd-fme
echo Any issues, Please report to either
echo https://github.com/lwvmobile/dsd-fme/issues
echo https://forums.radioreference.com/threads/dsd-fme.438137/
else
echo
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
fi

View File

@@ -0,0 +1,23 @@
#! /bin/bash
clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
echo This will clone, build, and install DSD-FME only.
echo If you need dependencies installed, please run download-and-install.sh instead.
echo
read -p "Press enter to continue"
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig

67
download-and-install.sh Normal file
View File

@@ -0,0 +1,67 @@
#! /bin/bash
clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition Auto Installer
echo MBELib is considered a requirement on this build.
echo You must view this notice prior to continuing.
echo The Patent Notice can be found at the site below.
echo https://github.com/lwvmobile/mbelib#readme
echo Please confirm that you have viewed the patent notice by entering y below.
echo
echo y/N
read ANSWER
Y='y'
if [[ $Y == $ANSWER ]]; then
sudo apt update
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
echo ITPP Manual Build and Install has been temporarily removed from this script due to issues with older versions of Ubuntu.
echo Please check to see that libitpp-dev has successfully been downloaded and installed from the repo.
read -p "Press enter to continue"
#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 ..
git clone https://github.com/lwvmobile/mbelib
cd mbelib
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
cd ..
cd ..
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
mkdir build
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig
else
echo
echo Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.
fi

BIN
dsd-fme2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
dsd-fme3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

227
examples/Example_Usage.md Normal file
View File

@@ -0,0 +1,227 @@
### Example Usage and Notes!
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
```
-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
-fm dPMR, also may need to use -xd if inverted dPMR.
-fr DMR Mono, also may need to use -xr if inverted DMR.
-f1 P25P1
-f2 P25P2 (may need to specify wacn/sys/nac manually)
-fx X2-TDMA
-fy YSF
```
## Conventional Frequency "Fast Scanner"
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies as fast as possible 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 rapidly 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 fast scanner switch.
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.~~
Please Note: DMR Simplex may not behave well on fast 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`
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)
### 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:udp
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)
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
```
## 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++ (Tested and Working on EDACS/EDACS-EA with Provoice, Analog Voice Monitoring and Per Call is Experimental)
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
--NXDN48 Trunking (standard band plan) with SDR++ (untested for frequency accuracy)
`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
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 - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
2 - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
0 - Toggle Audio Smoothing - May produce crackling if enabled on RTL/TCP or wav/bin files
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)
```
## 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
```

185
examples/Install_Notes.md Normal file
View File

@@ -0,0 +1,185 @@
## How to clone 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 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/main/download-and-install.sh
chmod +x download-and-install.sh
./download-and-install.sh
```
### Arch Based Distros:
```
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/v2.1b/download-and-install-Arch.sh
chmod +x download-and-install-Arch.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/main/download-and-install-nodeps.sh
chmod +x download-and-install-nodeps.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
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
```
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") This version of MBELib is 1.3.2 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 future compatibility issues.
```
git clone https://github.com/lwvmobile/mbelib
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.
`sudo cp libmbe* /usr/lib`
Finish by running these steps to clone and build DSD-FME.
```
git clone https://github.com/lwvmobile/dsd-fme
cd dsd-fme
sudo cp tone8.wav /usr/share/
sudo cp tone24.wav /usr/share/
sudo cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
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
cp tone8.wav /usr/share/
cp tone24.wav /usr/share/
cp tone48.wav /usr/share/
chmod 777 /usr/share/tone8.wav
chmod 777 /usr/share/tone24.wav
chmod 777 /usr/share/tone48.wav
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
```
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 cp tone48.wav /usr/share/
sudo chmod 777 /usr/share/tone8.wav
sudo chmod 777 /usr/share/tone24.wav
sudo chmod 777 /usr/share/tone48.wav
```

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

49
examples/trunking.sh Normal file
View File

@@ -0,0 +1,49 @@
#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 QPSK (Simulcast)
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -m2 -N 2> log.ans
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -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/EDACS-EA Digital Only
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
#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

View File

@@ -17,7 +17,8 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
//pretty pretty colors
//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"
@@ -26,6 +27,16 @@
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#else
#define KNRM ""
#define KRED ""
#define KGRN ""
#define KYEL ""
#define KBLU ""
#define KMAG ""
#define KCYN ""
#define KWHT ""
#endif
#include "config.h"
#include <stdio.h>
@@ -63,7 +74,11 @@
#include <locale.h>
#include <ncurses.h>
static volatile int exitflag;
#ifdef USE_CODEC2
#include <codec2/codec2.h>
#endif
extern volatile uint8_t exitflag; //fix for issue #136
//group csv import struct
typedef struct
@@ -259,6 +274,7 @@ typedef struct
int rtl_udp_port;
int rtl_bandwidth;
int rtl_started;
long int rtl_rms;
int monitor_input_audio;
int pulse_raw_rate_in;
int pulse_raw_rate_out;
@@ -297,6 +313,9 @@ typedef struct
int inverted_ysf;
short int aggressive_framesync;
int frame_m17;
int inverted_m17;
FILE *symbolfile;
int call_alert;
@@ -325,7 +344,9 @@ typedef struct
int p25_trunk; //experimental P25 trunking with RIGCTL (or RTLFM)
int p25_is_tuned; //set to 1 if currently on VC, set back to 0 if on CC
int trunk_hangtime; //hangtime in seconds before tuning back to CC
float trunk_hangtime; //hangtime in seconds before tuning back to CC
int scanner_mode; //experimental -- use the channel map as a conventional scanner, quicker tuning, but no CC
//csv import filenames
char group_in_file[1024];
@@ -344,6 +365,9 @@ typedef struct
uint8_t dmr_dmrla_is_set; //flag to tell us dmrla is set by the user
uint8_t dmr_dmrla_n; //n value for dmrla
//DMR Late Entry
uint8_t dmr_le; //user option to turn on or turn off late entry for enc identifiers
//Trunking - Use Group List as Allow List
uint8_t trunk_use_allow_list;
@@ -356,13 +380,19 @@ typedef struct
//Trunking - Tune Data Calls
uint8_t trunk_tune_data_calls;
//Trunking - Tune Enc Calls (P25 only on applicable grants with svc opts)
uint8_t trunk_tune_enc_calls;
//OSS audio - slot preference
uint8_t slot_preference;
int slot_preference;
//'DSP' Format Output
uint8_t use_dsp_output;
char dsp_out_file[2048];
//Use P25p1 heuristics
uint8_t use_heuristics;
} dsd_opts;
typedef struct
@@ -384,6 +414,10 @@ typedef struct
float *audio_out_temp_buf_p;
float audio_out_temp_bufR[160];
float *audio_out_temp_buf_pR;
//analog/raw signal audio buffers
short analog_out[960];
int analog_sample_counter;
//
int audio_out_idx;
int audio_out_idx2;
int audio_out_idxR;
@@ -538,8 +572,8 @@ typedef struct
//new stuff below here
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte]
uint8_t cap_plus_csbk_bits[12*8*8]; //CSBK Cap+ FL initial and appended block bit storage
uint8_t cap_plus_block_num; //received block number storage
uint8_t cap_plus_csbk_bits[2][12*8*8]; //CSBK Cap+ FL initial and appended block bit storage, by slot
uint8_t cap_plus_block_num[2]; //received block number storage -- per timeslot
uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
@@ -554,6 +588,7 @@ typedef struct
char dmr_lrrp_gps[2][200]; //2 slots by 99 char string for string lrrp gps
char dmr_site_parms[200]; //string for site/net info depending on type of DMR system (TIII or Con+)
char call_string[2][200]; //string for call information
char active_channel[31][200]; //string for storing and displaying active trunking channels
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
@@ -595,6 +630,7 @@ typedef struct
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
//iden freq storage for frequency calculations
int p25_chan_tdma[16]; //set from iden_up vs iden_up_tdma
int p25_chan_iden;
int p25_chan_type[16];
int p25_trans_off[16];
@@ -620,6 +656,7 @@ typedef struct
int dmr_vc_lcn;
int dmr_vc_lsn;
int dmr_tuned_lcn;
uint16_t dmr_cc_lpcn; //dmr t3 logical physical channel number
//edacs
int ea_mode;
@@ -640,6 +677,7 @@ typedef struct
int lcn_freq_roll; //number we have 'rolled' to in search of the CC
time_t last_cc_sync_time; //use this to start hunting for CC after signal lost
time_t last_vc_sync_time; //flag for voice activity bursts, tune back on con+ after more than x seconds no voice
time_t last_active_time; //time the a 'call grant' was received, used to clear the active_channel strings after x seconds
int is_con_plus; //con_plus flag for knowing its safe to skip payload channel after x seconds of no voice sync
//new nxdn stuff
@@ -651,13 +689,21 @@ typedef struct
uint8_t nxdn_sacch_frame_segcrc[4];
uint8_t nxdn_alias_block_number;
char nxdn_alias_block_segment[4][4][8];
//site/srv/cch info
char nxdn_location_category[14];
uint32_t nxdn_location_sys_code;
uint16_t nxdn_location_site_code;
//channel access information
uint8_t nxdn_rcn;
uint8_t nxdn_base_freq;
uint8_t nxdn_step;
uint8_t nxdn_bw;
//multi-key array
unsigned long long int rkey_array[0xFFFF];
int keyloader; //let us know the keyloader is active
//dmr late entry mi
uint64_t late_entry_mi_fragment[2][7][3];
@@ -672,14 +718,63 @@ typedef struct
//Upsampled Audio Smoothing
uint8_t audio_smoothing;
//YSF Fusion Call Strings and Info
uint8_t ysf_dt; //data type -- VD1, VD2, Full Rate, etc.
uint8_t ysf_fi; //frame information -- HC, CC, TC
uint8_t ysf_cm; //group or private call
char ysf_tgt[11];
char ysf_src[11];
char ysf_upl[11];
char ysf_dnl[11];
char ysf_rm1[6];
char ysf_rm2[6];
char ysf_rm3[6];
char ysf_rm4[6];
char ysf_txt[21][21]; //text storage blocks
//M17 Storage
uint8_t m17_lsf[360];
uint8_t m17_str_dt; //stream contents
unsigned long long int m17_dst;
unsigned long long int m17_src;
uint8_t m17_can;
char m17_dst_csd[20];
char m17_src_csd[20];
char m17_src_str[50];
char m17_dst_str[50];
uint8_t m17_meta[16]; //packed meta
uint8_t m17_enc; //enc type
uint8_t m17_enc_st; //scrambler or data subtye
//Codec2
#ifdef USE_CODEC2
struct CODEC2 *codec2_3200; //M17 fullrate
struct CODEC2 *codec2_1600; //M17 halfrate
#endif
} dsd_state;
/*
* Frame sync patterns
*/
#define FUSION_SYNC "31111311313113131131" //HA!
#define INV_FUSION_SYNC "13333133131331313313" //HA!
//The inverse of LSF also seems to be Stream Frame Type, only going to work on Stream mode for now
#define M17_LSF "11113313"
#define M17_STR "33331131"
//alternating with last symbol opposite of first symbol of LSF
#define M17_PRE "31313131"
#define M17_PIV "13131313"
#define M17_PRE_LSF "3131313133331131" //Preamble + LSF
#define M17_PIV_LSF "1313131311113313" //Preamble + LSF
// #define M17_BRT "31331111"
// #define M17_PKT "13113333"
#define FUSION_SYNC "31111311313113131131"
#define INV_FUSION_SYNC "13333133131331313313"
#define INV_P25P1_SYNC "333331331133111131311111"
#define P25P1_SYNC "111113113311333313133333"
@@ -730,6 +825,30 @@ typedef struct
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
//EDACS/PV EOT dotting sequence
#define DOTTING_SEQUENCE_A "131313131313131313131313131313131313131313131313" //0xAAAA...
#define DOTTING_SEQUENCE_B "313131313131313131313131313131313131313131313131" //0x5555...
//define the provoice conventional string pattern to default 85/85 if not enabled, else mute it so we won't double sync on accident in frame_sync
#ifdef PVCONVENTIONAL
#define PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
#define INV_PROVOICE_CONV "00000000000000000000000000000000" //all zeroes should be unobtainable string in the frame_sync synctests
#else
#define PROVOICE_CONV "13131333111311311313131313131313" //TX 85 RX 85 (default programming value)
#define INV_PROVOICE_CONV "31313111333133133131313131313131" //TX 85 RX 85 (default programming value)
#endif
//we use the short sync instead of the default 85/85 when PVCONVENTIONAL is defined by cmake
#define PROVOICE_CONV_SHORT "1313133311131131" //16-bit short pattern, last 16-bits change based on TX an RX values
#define INV_PROVOICE_CONV_SHORT "3131311133313313"
//In this pattern (inverted polarity, the norm for PV) 3 is bit 0, and 1 is bit 1 (2 level GFSK)
//same pattern //TX //RX
// Sync Pattern = 3131311133313313 31331131 31331131 TX/RX 77 -- 31331131 symbol = 01001101 binary = 77 decimal
// Sync Pattern = 3131311133313313 33333333 33333333 TX/RX 0 -- 33333333 symbol = 00000000 binary = 0 decimal
// Sync Pattern = 3131311133313313 33333331 33333331 TX/RX 1 -- 33333331 symbol = 00000001 binary = 1 decimal
// Sync Pattern = 3131311133313313 13131133 13131133 TX/RX 172 -- 13131133 symbol = 10101100 binary = 172 decimal
// Sync Pattern = 3131311133313313 11333111 11333111 TX/RX 199 -- 11333111 symbol = 11000111 binary = 199 decimal
// Sync Pattern = 3131311133313313 31313131 31313131 TX/RX 85 -- 31313131 symbol = 01010101 binary = 85 decimal
#define EDACS_SYNC "313131313131313131313111333133133131313131313131"
#define INV_EDACS_SYNC "131313131313131313131333111311311313131313131313"
@@ -764,6 +883,7 @@ void openAudioInDevice (dsd_opts * opts);
int getDibit (dsd_opts * opts, dsd_state * state);
int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal);
int digitize (dsd_opts* opts, dsd_state* state, int symbol);
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
@@ -811,6 +931,9 @@ int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
void upsample (dsd_state * state, float invalue);
void processDSTAR (dsd_opts * opts, dsd_state * state);
//new p25lcw
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors);
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
void processHDU (dsd_opts * opts, dsd_state * state);
void processLDU1 (dsd_opts * opts, dsd_state * state);
@@ -822,15 +945,17 @@ void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
void processDSTAR_HD (dsd_opts * opts, dsd_state * state);
void processYSF(dsd_opts * opts, dsd_state * state); //YSF
void processM17STR(dsd_opts * opts, dsd_state * state); //M17 (STR)
void processM17LSF(dsd_opts * opts, dsd_state * state); //M17 (LSF)
void processP2(dsd_opts * opts, dsd_state * state); //P2
void processTSBK(dsd_opts * opts, dsd_state * state);
void processTSBK(dsd_opts * opts, dsd_state * state); //P25 Trunking Single Block
void processMPDU(dsd_opts * opts, dsd_state * state); //P25 Multi Block PDU (SAP 0x61 FMT 0x15 or 0x17 for Trunking Blocks)
short dmr_filter(short sample);
short nxdn_filter(short sample);
short dpmr_filter(short sample);
short m17_filter(short sample);
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr);
/* Global functions */
uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength);
void ncursesOpen (dsd_opts * opts, dsd_state * state);
void ncursesPrinter (dsd_opts * opts, dsd_state * state);
@@ -839,10 +964,15 @@ void ncursesClose ();
//new NXDN Functions start here!
void nxdn_frame (dsd_opts * opts, dsd_state * state);
void nxdn_descramble (uint8_t dibits[], int len);
//nxdn deinterleaving/depuncturing functions
void nxdn_deperm_facch (dsd_opts * opts, dsd_state * state, uint8_t bits[144]);
void nxdn_deperm_sacch (dsd_opts * opts, dsd_state * state, uint8_t bits[60]);
void nxdn_deperm_cac (dsd_opts * opts, dsd_state * state, uint8_t bits[300]);
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348]);
void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type);
//type-d 'idas' deinterleaving/depuncturing functions
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction);
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type);
//end
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
@@ -852,6 +982,7 @@ static uint8_t crc6(const uint8_t buf[], int len);
static uint16_t crc12f(const uint8_t buf[], int len);
static uint16_t crc15(const uint8_t buf[], int len);
static uint16_t crc16cac(const uint8_t buf[], int len);
static uint8_t crc7_scch(uint8_t bits[], int len); //converted from op25 crc6
/* NXDN Convolution functions */
void CNXDNConvolution_start(void);
@@ -874,7 +1005,9 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void NXDN_decode_srv_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message);
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id);
void NXDN_decode_adj_site(dsd_opts * opts, dsd_state * state, uint8_t * Message);
//Type-D SCCH Message Decoder
void NXDN_decode_scch(dsd_opts * opts, dsd_state * state, uint8_t * Message, uint8_t direction);
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
@@ -914,6 +1047,9 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18]); //simplier trellis decoder
void beeper (dsd_opts * opts, dsd_state * state, int type); //the tone beeper function
void dmr_gateway_identifier (uint32_t source, uint32_t target); //translate special addresses
//Embedded Alias and GPS
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
@@ -948,10 +1084,15 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
bool Hamming17123(uint8_t* d);
uint8_t crc8(uint8_t bits[], unsigned int len);
bool crc8_ok(uint8_t bits[], unsigned int len);
//modified CRC functions for SB/RC
uint8_t crc7(uint8_t bits[], unsigned int len);
uint8_t crc3(uint8_t bits[], unsigned int len);
uint8_t crc4(uint8_t bits[], unsigned int len);
//LFSR code courtesy of https://github.com/mattames/LFSR/
//LFSR and LFSRP code courtesy of https://github.com/mattames/LFSR/
void LFSR(dsd_state * state);
void LFSRP(dsd_state * state);
void LFSRN (char * BufferIn, char * BufferOut, dsd_state * state);
void LFSR64(dsd_state * state);
@@ -993,6 +1134,7 @@ bool QR_16_7_6_decode(unsigned char *rxBits);
void InitAllFecFunction(void);
void resetState (dsd_state * state);
void reset_dibit_buffer(dsd_state * state);
void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]);
//P25 PDU Handler
@@ -1032,13 +1174,15 @@ int UDPBind (char *hostname, int portno);
//EDACS
void edacs(dsd_opts * opts, dsd_state * state);
unsigned long long int edacs_bch (unsigned long long int message);
unsigned long long int edacs_bch (unsigned long long int message);
void eot_cc(dsd_opts * opts, dsd_state * state); //end of TX return to CC
//csv imports
int csvGroupImport(dsd_opts * opts, dsd_state * state);
int csvLCNImport(dsd_opts * opts, dsd_state * state);
int csvChanImport(dsd_opts * opts, dsd_state * state);
int csvKeyImport(dsd_opts * opts, dsd_state * state);
int csvKeyImportDec(dsd_opts * opts, dsd_state * state);
int csvKeyImportHex(dsd_opts * opts, dsd_state * state);
#ifdef __cplusplus
extern "C" {
@@ -1049,22 +1193,17 @@ void open_rtlsdr_stream(dsd_opts *opts);
void cleanup_rtlsdr_stream();
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state);
void rtlsdr_sighandler();
void rtl_dev_tune(dsd_opts * opts, long int frequency);
long int rtl_return_rms();
void rtl_clean_queue();
#endif
//DMR TRELLIS
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload);
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits);
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload);
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits);
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points);
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits);
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits);
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload);
//Phase 2 Helper Functions
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
int isch_lookup (unsigned long long int isch); //isch map lookup
int isch_lookup (uint64_t isch); //isch map lookup
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
int crc16_lb_bridge (int payload[190], int len);
int crc12_xb_bridge (int payload[190], int len);

16
rebuild.sh Normal file
View File

@@ -0,0 +1,16 @@
#! /bin/bash
clear
echo DSD-FME Digital Speech Decoder - Florida Man Edition
echo Automatic Git Pull and Rebuild
echo
sleep 1
##Open your clone folder##
git pull
sleep 2
##cd into your build folder##
cd build
cmake ..
make -j `nproc`
sudo make install
sudo ldconfig

136
src/dmr_34.c Normal file
View File

@@ -0,0 +1,136 @@
/*-------------------------------------------------------------------------------
* dmr_34.c
* DMR 3/4 Rate Simple Trellis Decoder
*
* LWVMOBILE
* 2023-08 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 contellation 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};
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
{
int i, j;
uint32_t irr_err = 0;
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 -- point[0] should be zero
// fprintf (stderr, "\n P =");
// for (i = 0; i < 49; i++)
// fprintf (stderr, " %02d", point[i]);
//free-bee on err correction, point[0] should always be zero (flush bits)
point[0] = 0;
//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 position of error and state value
// fprintf (stderr, " %d:%d;", i, state);
//Make a hard decision and flip point to fit in current state
point[i] ^= 7; //lucky number 7 (0111)
//NOTE: Ideally, a full path metric to find the surviving path
//is the best way to correct this, but it is also complex and no garauntee to fix errs
//decrement one and try again
if (i != 0) 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;
if (1 == 1) //irr_err == 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, " ERR = %d", irr_err);
return (irr_err);
}

View File

@@ -34,6 +34,35 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
uint32_t target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[16], 24); //destination llid
uint32_t source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[40], 24); //source llid
//extra tgt/src handling for XPT
uint8_t target_hash[24];
uint8_t tg_hash = 0;
uint8_t is_xpt = 0;
//set flag if XPT
if (strcmp (state->dmr_branding_sub, "XPT ") == 0) is_xpt = 1;
//truncate tgt/src to 16-bit values if XPT
if (is_xpt == 1)
{
target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16); //destination llid
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16); //source llid
if (gi == 0)
{
for (int i = 0; i < 16; i++) target_hash[i] = dheader_bits[24+i];
tg_hash = crc8 (target_hash, 16);
}
}
uint8_t is_cap = 0;
if (strcmp (state->dmr_branding_sub, "Cap+ ") == 0) is_cap = 1;
if (is_cap)
{
//truncate tg on group? or just on private/individual data?
if (gi == 0) target = (uint32_t)ConvertBitIntoBytes(&dheader_bits[24], 16);
source = (uint32_t)ConvertBitIntoBytes(&dheader_bits[48], 16);
}
//store source for dmr pdu packet handling (lrrp) when not available in completed message
if (dpf != 15) state->dmr_lrrp_source[slot] = source;
@@ -97,8 +126,8 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
fprintf (stderr, "\n");
fprintf (stderr, " Slot %d Data Header - ", slot+1);
if (gi == 1 && dpf != 15) fprintf(stderr, "GROUP - ");
if (gi == 0 && dpf != 15) fprintf(stderr, "INDIV - ");
if (gi == 1 && dpf != 15) fprintf(stderr, "Group - ");
if (gi == 0 && dpf != 15) fprintf(stderr, "Indiv - ");
if (dpf == 0) fprintf (stderr, "Unified Data Transport (UDT) ");
else if (dpf == 1) fprintf (stderr, "Response Packet ");
@@ -112,6 +141,9 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
if (a == 1 && dpf != 15) fprintf(stderr, "- Response Requested ");
if (dpf != 15) fprintf (stderr, "- Source: %d Target: %d ", source, target);
//include the hash value if this is an XPT and if its IND data
if (dpf != 15 && is_xpt == 1 && gi == 0) fprintf (stderr, "Hash: %d ", tg_hash);
//sap string handling
if (dpf == 15) sap = p_sap;
@@ -128,12 +160,12 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
if (dpf == 15)
{
if (p_mfid == 0x10) sprintf (mfid_string, "%s", "Motorola");
else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait ");
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera ");
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera ");
else if (p_mfid == 0x58) sprintf (mfid_string, "%s", "Tait");
else if (p_mfid == 0x68) sprintf (mfid_string, "%s", "Hytera");
else if (p_mfid == 0x08) sprintf (mfid_string, "%s", "Hytera");
else if (p_mfid == 0x06) sprintf (mfid_string, "%s", "Trid/Mot");
else if (p_mfid == 0x00) sprintf (mfid_string, "%s", "Standard");
else sprintf (mfid_string, "%s", "Other ");
else sprintf (mfid_string, "%s", "Other");
}
//udt format string handling
@@ -324,6 +356,7 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
state->data_conf_data[slot] = 0;
state->data_block_counter[slot] = 1;
state->data_header_blocks[slot] = 1;
state->data_header_format[slot] = 7;
}
@@ -384,7 +417,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
uint32_t CRCExtracted = 0;
uint32_t IrrecoverableErrors = 0;
uint8_t dmr_pdu_sf_bits[8*8*50]; //give plenty of space so we don't go oob
uint8_t dmr_pdu_sf_bits[8*24*50]; //give plenty of space so we don't go oob
//MBC Header and Block CRC
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
@@ -740,11 +773,12 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
memset (state->dmr_lrrp_source, 0, sizeof(state->dmr_lrrp_source));
memset (state->dmr_cach_fragment, 1, sizeof (state->dmr_cach_fragment));
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
memset (state->cap_plus_block_num, 0, sizeof(state->cap_plus_block_num));
memset (state->data_header_valid, 0, sizeof(state->data_header_valid));
memset (state->data_header_format, 7, sizeof(state->data_header_format));
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//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", "");
}

View File

@@ -96,6 +96,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
//Run Loop while the getting is good
while (loop == 1) {
memset (ambe_fr, 0, sizeof(ambe_fr));
memset (ambe_fr2, 0, sizeof(ambe_fr2));
memset (ambe_fr3, 0, sizeof(ambe_fr3));
internalslot = -1; //reset here so we know if this value is being set properly
for(i = 0; i < 12; i++)
{
@@ -339,8 +343,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
//process embedded link control
fprintf (stderr, "\n");
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
//check the single burst/reverse channel opportunity
dmr_sbrc (opts, state, power);
//check the single burst/reverse channel opportunity -- moved
// dmr_sbrc (opts, state, power);
}
if (internalslot == 1 && vc2 == 6)
@@ -348,8 +353,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
//process embedded link control
fprintf (stderr, "\n");
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
//check the single burst/reverse channel opportunity
dmr_sbrc (opts, state, power);
//check the single burst/reverse channel opportunity -- moved
// dmr_sbrc (opts, state, power);
}
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
@@ -361,25 +367,16 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
memcpy (m2, ambe_fr2, sizeof(m2));
memcpy (m3, ambe_fr3, sizeof(m3));
// if ( opts->audio_in_type == 5 && internalslot == 0 && state->dmrburstR != 16 ) //(OSS shim)
// {
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
// }
// if ( opts->audio_in_type == 5 && internalslot == 1 && state->dmrburstL != 16 ) //(OSS shim)
// {
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
// }
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
cach_err = dmr_cach (opts, state, cachdata);
fprintf (stderr, "\n");
if (opts->payload == 0) fprintf (stderr, "\n");
// run alg refresh after vc6 ambe processing
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
@@ -501,6 +498,10 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
char ambe_fr2[4][24];
char ambe_fr3[4][24];
memset (ambe_fr, 0, sizeof(ambe_fr));
memset (ambe_fr2, 0, sizeof(ambe_fr2));
memset (ambe_fr3, 0, sizeof(ambe_fr3));
//memcpy of ambe_fr for late entry
char m1[4][24];
char m2[4][24];
@@ -724,7 +725,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
cach_err = dmr_cach (opts, state, cachdata);
fprintf (stderr, "\n");
if (opts->payload == 0) fprintf (stderr, "\n");
//update voice sync time for trunking purposes (particularly Con+)
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);

File diff suppressed because it is too large Load Diff

View File

@@ -258,7 +258,6 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
else
{
SlotTypeOk = -1;
SlotTypeOk = 0;
goto END;
}
@@ -336,13 +335,15 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
else if (opts->audio_in_type == 3) //rtl_fm tuning
{
//UDP command to tune the RTL dongle
rtl_udp_tune(opts, state, state->p25_cc_freq);
#ifdef USE_RTLSDR
rtl_dev_tune(opts, state->p25_cc_freq);
#endif
}
opts->p25_is_tuned = 0;
//zero out vc frequencies
state->p25_vc_freq[0] = 0;
state->p25_vc_freq[1] = 0;
memset (state->active_channel, 0, sizeof(state->active_channel));
state->last_cc_sync_time = time(NULL);
state->is_con_plus = 0; //con+ flag off
}

View File

@@ -45,6 +45,13 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
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];
@@ -411,34 +418,29 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
}
//the ugly one
//the sexy one
if (is_trellis)
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 1;
bool trellis_good = TRUE;
uint8_t tdibits[98];
memset (tdibits, 0, sizeof(tdibits));
//reconstitute info bits into reverse ordered dibits for the trellis decoder
//reconstitute info bits into dibits for the trellis decoder
for (i = 0; i < 98; i++)
{
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
}
tdibits[i] = (info[i*2] << 1) | info[i*2+1];
unsigned char TrellisReturn[18];
uint8_t TrellisReturn[18];
memset (TrellisReturn, 0, sizeof(TrellisReturn));
IrrecoverableErrors = dmr_34(tdibits, TrellisReturn);
trellis_good = CDMRTrellisDecode(tdibits, TrellisReturn);
if (trellis_good == TRUE) IrrecoverableErrors = 0;
// else (fprintf (stderr, " Trellis Failure")); //debug print
//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++) //18
{
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
}
for (i = 0; i < pdu_len; i++)
DMR_PDU[i] = TrellisReturn[i+pdu_start];
for(i = 0, j = 0; i < 18; i++, j+=8)
{
@@ -464,7 +466,6 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
//confirmed working now!
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];
@@ -475,10 +476,8 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else
{
// IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
state->data_block_crc_valid[slot][blockcounter] = 0;
}
}
@@ -498,7 +497,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
}
if (is_full) //Rate 1 Data
if (is_full) //Rate 1 Data -- todo: fix padding bits, the four padding bits are on bit 96,97,98,99
{
CRCExtracted = 0;
CRCComputed = 0;
@@ -598,7 +597,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
// }
if (IrrecoverableErrors != 0 && databurst != 0x09) //&& databurst != 0x05
if (IrrecoverableErrors != 0 && databurst != 0x08 && databurst != 0x09) //&& databurst != 0x05
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " (FEC ERR)");

View File

@@ -84,6 +84,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
if (slot == 0) state->dmr_flco = flco;
else state->dmr_flcoR = flco;
//FID 0x10 and FLCO 0x14, 0x15, 0x16 and 0x17 confirmed as Moto EMB Alias
//Can probably assume FID 0x10 FLCO 0x18 is Moto EMB GPS -- to be tested
if ( fid == 0x10 && (flco == 0x14 || flco == 0x15 || flco == 0x16 || flco == 0x17 || flco == 0x18) )
{
flco = flco - 0x10;
fid = 0;
}
//Embedded Talker Alias Header Only (format and len storage)
if ( (fid == 0 || fid == 0x68) && type == 3 && flco == 0x04)
{
@@ -113,8 +121,8 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
}
//Unknown CapMax/Moto Things -- 0x14, 0x15, 0x16 are new ones on emb
if (fid == 0x10 && (flco == 0x08 || flco == 0x28 || flco == 0x14 || flco == 0x15 || flco == 0x16))
//Unknown CapMax/Moto Things
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
{
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
@@ -164,7 +172,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//look for any Hytera XPT system, adjust TG to 16-bit allocation
//Groups use only 8 out of 16, but 16 always seems to be allocated
//private calls use 16-bit target values hased to 8-bit in the site status csbk
//private calls use 16-bit target values hashed to 8-bit in the site status csbk
//the TLC preceeds the VLC for a 'handshake' call setup in XPT
//truncate if XPT is set
@@ -178,11 +186,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
tg_hash = crc8 (target_hash, 16);
}
//XPT Call 'Grant' Setup Occurs in TLC (TermLC Handshake) with a flco 0x09
//XPT Call 'Grant/Alert' Setup Occurs in TLC with a flco 0x09
if (fid == 0x68 && flco == 0x09)
{
//The CSBK always uses an 8-bit TG; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
//It seems that private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
//The CSBK always uses an 8-bit TG/TGT; The White Papers (user manuals) say 8-bit TG and 16-bit SRC addressing
//private calls and indiv data calls use a hash of their 8 bit tgt values in the CSBK
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //This is consistent with an LCN value, not an LSN value
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 4); //24 and 4 on 0x09
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[28], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
@@ -190,86 +199,69 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16); //16-bit allocation
//the bits that are left behind
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Where the SVC bits would usually be
xpt_res_a = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //after the xpt_int channel, before the free repeater channel -- call being established = 7; call connected = 0; ??
xpt_res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 8); //where the first 8 bits of the SRC would be
xpt_res_c = (uint8_t)ConvertBitIntoBytes(&lc_bits[72], 8); //some unknown 8 bit value after the SRC
//speculation: 16,4 may be the current repeater channel this call will occur on? or the channel to interrupt?, could also be 8 bits?
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4);
//the crc8 hash is the value represented in the CSBK when dealing with private calls
for (int i = 0; i < 16; i++) target_hash[i] = lc_bits[32+i];
tg_hash = crc8 (target_hash, 16); //This is a different poly, but using as placeholder
tg_hash = crc8 (target_hash, 16);
fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
// Here are some of the RIDs with hash address seen in that sample:
// 930 = 88
// 9317 = 198
// 10002 = 187
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK [%X] ", xpt_hand);
if (opts->payload == 1) fprintf(stderr, "CH=%X ", xpt_int+1); //repeater channel to 'interrupt' with this call?
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
// if (opts->payload == 1) fprintf(stderr, "RS [%02X][%02X][%02X] ", xpt_res_a, xpt_res_b, xpt_res_c);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "TGT=%u SRC=%u ", target, source);
fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group "); //according to observation
else fprintf (stderr, "Private "); //according to observation
fprintf (stderr, "Call Protect ");
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "F-Rpt %d", xpt_free+1);
//Group ID ranges from 1 to 240; emergency group call ID ranges from 250 to 254; all call ID is 255.
if (reserved == 1)
{
fprintf (stderr, "Group "); //according to observation
if (target > 248 && target < 255) fprintf (stderr, "Emergency ");
if (target == 255) fprintf (stderr, "All ");
}
else fprintf (stderr, "Private "); //according to observation
fprintf (stderr, "Call Alert "); //Alert or Grant
//reorganized all the 'extra' data to a second line and added extra verbosity
if (opts->payload == 1) fprintf (stderr, "\n ");
if (opts->payload == 1) fprintf (stderr, "%s", KYEL);
//only display the hashed tgt value if its a private call and not a group call
if (reserved == 0 && opts->payload == 1) fprintf(stderr, "TGT Hash=%d; ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "HSK=%X; ", xpt_hand);
//extra verbosity on handshake types found in the patent
if (opts->payload == 1)
{
fprintf (stderr, "Handshake - ");
if (xpt_hand == 0) fprintf (stderr, "Ordinary; ");
else if (xpt_hand == 1) fprintf (stderr, "Callback/Alarm Interrupt; ");
else if (xpt_hand == 2) fprintf (stderr, "Release Channel Interrupt; ");
else fprintf (stderr, "Reserved; ");
}
// if (opts->payload == 1)
// {
// if (xpt_res_a == 0) fprintf (stderr, "Call Connected; ");
// if (xpt_res_a == 1) fprintf (stderr, "Data Call Request; ");
// if (xpt_res_a == 7) fprintf (stderr, "Voice Call Request; ");
// if (xpt_res_a == 2) fprintf (stderr, "Unknown Status; ");
// }
//logical repeater channel, not the logical slot value in the CSBK
if (opts->payload == 1) fprintf(stderr, "Call on LCN %d; ", xpt_int); //LCN channel call or 'interrupt' will occur on
// if (opts->payload == 1) fprintf(stderr, "RS A[%01X]B[%02X]C[%02X]; ", xpt_res_a, xpt_res_b, xpt_res_c); //leftover bits
if (opts->payload == 1) fprintf (stderr, "Free LCN %d; ", xpt_free); //current free repeater LCN channel
fprintf (stderr, "%s ", KNRM);
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free+1);
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
is_xpt = 1;
goto END_FLCO;
}
//XPT 'Handshake' -- not observed as of yet on any samples
if ( fid == 0x68 && (flco == 0x2E || flco == 0x2F) )
{
//all below is according to the patent, but never observed on any samples I have
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //24-bit values according to patent
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 24); //24-bit values according to patent
xpt_free = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4); //16 and 4 on 2E and 2F
xpt_hand = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 4); //handshake kind: 0 - ordinary; 1-2 Interrupts; 3-15 reserved;
xpt_int = (uint8_t)ConvertBitIntoBytes(&lc_bits[24], 8); //Interrupt Designated Channel (No idea?)
fprintf (stderr, "%s \n", KGRN);
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1) fprintf(stderr, "HASH=%d ", tg_hash);
// if (opts->payload == 1) fprintf(stderr, "HSK=[%X] ", xpt_hand);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "Hytera XPT ");
if (reserved == 1) fprintf (stderr, "Group ");
else fprintf (stderr, "Private ");
fprintf (stderr, "Call ");
if (flco == 0x2E) fprintf (stderr, "Request ");
if (flco == 0x2F) fprintf (stderr, "Response ");
fprintf (stderr, "%s ", KNRM);
is_xpt = 1;
goto END_FLCO;
}
//Hytera XPT "something" -- seen on Embedded
if (fid == 0x68 && flco == 0x13)
//Hytera XPT 'Others' -- moved the patent opcodes here as well for now
if ( fid == 0x68 && (flco == 0x13 || flco == 0x31 || flco == 0x2E || flco == 0x2F) )
{
if (type == 1) fprintf (stderr, "%s \n", KCYN);
if (type == 2) fprintf (stderr, "%s \n", KCYN);
@@ -350,6 +342,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
state->payload_miR = 0;
state->payload_keyidR = 0;
}
}
@@ -369,7 +362,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf (stderr, " SLOT %d ", state->currentslot+1);
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1 && is_xpt == 1) fprintf(stderr, "HASH=%d ", tg_hash);
if (opts->payload == 1 && is_xpt == 1 && flco == 0x3) fprintf(stderr, "HASH=%d ", tg_hash);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
@@ -395,7 +388,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf (stderr, "Private ");
}
}
else if (flco == 0x3) //UU_V_Ch_Usr -- still valid on hytera VLC
else if (flco == 0x3) //UU_V_Ch_Usr
{
sprintf (state->call_string[slot], " Private ");
fprintf (stderr, "Private ");
@@ -424,26 +417,21 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
//REMUS! Uncomment Line Below if desired
// else strcat (state->call_string[slot], " ");
//Motorola FID 0x10 Only
if (fid == 0x10)
if (1 == 1) //fid == 0x10
{
/* Check the "Service Option" bits */
if(so & 0x30)
if( (fid == 0x10) && (so & 0x20) ) //Motorola FID 0x10 Only
{
/* Experimentally determined with DSD+,
* is equal to 0x2, this is a TXI call */
if((so & 0x30) == 0x20)
{
//REMUS! Uncomment Line Below if desired
// strcat (state->call_string[slot], " TXI");
fprintf(stderr, "TXI ");
}
else
{
//REMUS! Uncomment Line Below if desired
// strcat (state->call_string[slot], " RES");
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
}
//REMUS! Uncomment Line Below if desired
// strcat (state->call_string[slot], " TXI");
fprintf(stderr, "TXI ");
}
if ( (fid == 0x10) && (so & 0x10) ) //Motorola FID 0x10 Only
{
//REMUS! Uncomment Line Below if desired
// strcat (state->call_string[slot], " RPT");
fprintf(stderr, "RPT "); //Short way of saying the next SF's VC6 will be pre-empted/repeat frames for the TXI backwards channel
}
if(so & 0x08)
{
@@ -501,7 +489,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
if (restchannel != -1)
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "Cap+ R-Ch %d", restchannel);
fprintf (stderr, "Rest LSN: %d", restchannel);
}
}
@@ -519,29 +507,68 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
}
}
if (state->K != 0 && fid == 0x10 && so & 0x40)
//BUGFIX: Include slot and algid so we don't accidentally print more than one loaded key
//this can happen on Missing PI header and LE when the keyloader has loaded a TG/Hash key and an RC4 key simultandeously
//subsequennt EMB would print two key values until call cleared out
if (state->K != 0 && fid == 0x10 && so & 0x40 && slot == 0 && state->payload_algid == 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "Key %lld ", state->K);
fprintf (stderr, "%s ", KNRM);
}
if (state->K != 0 && fid == 0x10 && so & 0x40 && slot == 1 && state->payload_algidR == 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "Key %lld ", state->K);
fprintf (stderr, "%s ", KNRM);
}
if (state->K1 != 0 && fid == 0x68 && so & 0x40)
if (state->K1 != 0 && fid == 0x68 && so & 0x40 && slot == 0 && state->payload_algid == 0)
{
fprintf (stderr, "\n");
if (state->K2 != 0) fprintf (stderr, "\n ");
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Key %010llX ", state->K1);
fprintf (stderr, "Key %010llX ", state->K1);
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
fprintf (stderr, "%s ", KNRM);
}
}
if (state->K1 != 0 && fid == 0x68 && so & 0x40 && slot == 1 && state->payload_algidR == 0)
{
if (state->K2 != 0) fprintf (stderr, "\n ");
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "Key %010llX ", state->K1);
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
fprintf (stderr, "%s ", KNRM);
}
if (slot == 0 && state->payload_algid == 0x21 && state->R != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "Key %010llX ", state->R);
fprintf (stderr, "%s ", KNRM);
}
if (slot == 1 && state->payload_algidR == 0x21 && state->RR != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, "Key %010llX ", state->RR);
fprintf (stderr, "%s ", KNRM);
}
}
END_FLCO:
//blank the call string here if its a TLC
if (type == 2) sprintf (state->call_string[slot], "%s", " "); //21 spaces
if (unk == 1 || pf == 1)
{
fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid);
fprintf (stderr, "%s", KNRM);
}
@@ -715,6 +742,7 @@ uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
fprintf (stderr, "%s", KRED);
fprintf (stderr, " SLCO CRC ERR");
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1) fprintf (stderr, "\n");
}
}
@@ -897,13 +925,13 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
else if (slco == 0x08)
{
//The Priority Repeater and Priority Hash values stem from SDRTrunk, but I've never seen these values not be zeroes
// fprintf (stderr, " SLCO Hytera XPT - Free RPT %d - PRI RPT %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
fprintf (stderr, " SLCO Hytera XPT - Free LCN %d - PRI LCN %d - PRI HASH: %02X", xpt_free, xpt_pri, xpt_hash);
//NOTE: on really busy systems, this free repeater assignment can lag due to the 4 TS requirment to get SLC
fprintf (stderr, " SLCO Hytera XPT - Free RPT %d ", xpt_free+1);
// fprintf (stderr, " SLCO Hytera XPT - Free LCN %d ", xpt_free);
sprintf (state->dmr_branding_sub, "XPT ");
//add string for ncurses terminal display
sprintf (state->dmr_site_parms, "Free RPT - %d ", xpt_free+1);
sprintf (state->dmr_site_parms, "Free LCN - %d ", xpt_free);
}
else fprintf (stderr, " SLCO Unknown - %d ", slco);
@@ -915,6 +943,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
{
fprintf (stderr, "[%02X]", slco_bytes[i]);
}
fprintf (stderr, "\n"); //if its a voice frame, we need the line break
}
fprintf (stderr, "%s", KNRM);
@@ -955,6 +984,10 @@ void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_b
uint8_t len = state->dmr_alias_len[slot];
uint8_t start; //starting position depends on context of block and format
//Cap Max Variation
uint8_t fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8);
if (fid == 0x10) block = block - 0x10; //CapMax adds 0x10 to its FLCO (block num) in its Embedded Aliasing
//there is some issue with the next three lines of code that prevent proper assignments, not sure what.
//if (block > 4) start = 16;
//else if (block == 4 && format > 0) start = 23; //8-bit and 16-bit chars

View File

@@ -13,6 +13,23 @@ void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc,
{
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);
@@ -34,6 +51,12 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
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) |
@@ -60,12 +83,22 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
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)
@@ -73,8 +106,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
if (state->payload_mi != mi_final)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
state->payload_mi = mi_final;
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_mi, mi_final);
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
@@ -89,8 +125,11 @@ void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
if (state->payload_miR != mi_final)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final);
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X ", state->payload_miR, mi_final);
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
@@ -161,13 +200,24 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
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 crc_okay = 0;
uint8_t crc7_okay = 0; //RC
uint8_t crc3_okay = 0; //TXI
uint8_t txi = 0; //SEE: https://patents.google.com/patent/US8271009B2
//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
@@ -181,9 +231,11 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
//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
//unknown what the other values are (see Cap+ 0x313 and 0x643)
//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;
@@ -193,106 +245,152 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
crc_extracted = crc_extracted | sbrc_return[i+4];
}
crc_extracted = crc_extracted ^ 0x7A;
crc_computed = crc7((uint8_t *) sbrc_return, 11);
if (crc_extracted == crc_computed) crc_okay = 1;
crc_computed = crc7((uint8_t *) sbrc_return, 7);
if (crc_extracted == crc_computed) crc7_okay = 1;
}
else crc_okay = 1; //SB
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people right now
else //if (txi == 1) //if TXI -- but TXI systems also carry the non-crc protected ENC identifiers
{
fprintf (stderr, "\n %s", KCYN);
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++)
{
sbrc_hex = sbrc_hex << 1;
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
fprintf (stderr, "%d", sbrc_return[i]);
}
fprintf (stderr, " - %03X", sbrc_hex);
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);
// }
if (crc_okay == 0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1) fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
}
fprintf (stderr, "\n");
}
//Disabling the lower portion until this can be completely ironed out
//sbrc_hex value of 0x313 seems to be some Cap+ Thing,
//also observed 0x643 on another cap+ system (site id, status? something?)
// uint8_t sbrc_opcode = sbrc_hex;
// uint8_t alg = sbrc_hex & 0x7;
// uint8_t key = (sbrc_hex >> 3) & 0xFF;
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
//this pattern seems to fit the multiple cap+ systems I've observed
//test on site '7' to make sure (works on 1 and 4)
// uint8_t cap_site = (sbrc_hex >> 4) & 0x7;
//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
// if (opts->payload == 1)
// {
// if (irr_err != 0) fprintf (stderr, "%s (FEC ERR) %d %s", KRED, irr_err, KNRM);
// if (irr_err == 0)
// {
// if (sbrc_hex == 0) ; //NULL
// else if (sbrc_hex == 0x313) //sbrc_hex == 0x313 and 0x643 (cap+ things)
// {
// //Cap+ Site ID seems to fit here on samples I've seen with the alternate SB signalling
// fprintf (stderr, "%s ", KYEL);
// fprintf (stderr, "\n ");
// fprintf (stderr, " Capacity Plus Site %d", cap_site);
// fprintf (stderr, "%s ", KNRM);
// }
// else
// {
//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 (slot == 0)
// {
// //key and alg only present SOME times, not all,
// //also, intermixed with other signalling
// //needs more study first!
// if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
// {
// if (opts->payload == 1)
// {
// fprintf (stderr, "%s ", KYEL);
// fprintf (stderr, "\n Slot 1");
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
// fprintf (stderr, "%s ", KNRM);
// }
// //needs more study before assignment
// // state->payload_keyid = key;
// // state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
// }
// }
if (opts->dmr_le == 1) //this will now require a user to switch it on or off until more testing/figuring can be done
{
if (irr_err != 0) fprintf (stderr, "\n%s SLOT %d SB/RC (FEC ERR) %d %s \n", KRED, slot, irr_err, KNRM);
if (irr_err == 0)
{
if (sbrc_hex == 0) ; //NULL, do nothing
// if (slot == 1)
// {
// if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
// {
// if (opts->payload == 1)
// {
// fprintf (stderr, "%s ", KYEL);
// fprintf (stderr, "\n Slot 2");
// fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
// fprintf (stderr, "%s ", KNRM);
// }
// //needs more study before assignment
// // state->payload_keyidR = key;
// // state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
// }
// }
//else if (placeholder for future conditions)
// {
// placeholder for future conditions
// }
// }
else if (crc7_okay == 1)
{
//do something with the reverse channel information
}
// }
// }
//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 && state->payload_keyid == 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");
state->payload_keyid = key;
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 && state->payload_keyidR == 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");
state->payload_keyidR = key;
state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
}
}
}
}
}
}
SBRC_END:
@@ -314,3 +412,50 @@ void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
}
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
}

View File

@@ -87,7 +87,11 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
//so getDibit doesn't know to invert it before it gets here
for (j = 0; j < 6; j++) {
state->dmrburstL = 16;
state->dmrburstL = 16;
memset (ambe_fr, 0, sizeof(ambe_fr));
memset (ambe_fr2, 0, sizeof(ambe_fr2));
memset (ambe_fr3, 0, sizeof(ambe_fr3));
for(i = 0; i < 12; i++)
{
@@ -370,7 +374,11 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
char ambe_fr[4][24];
char ambe_fr2[4][24];
char ambe_fr3[4][24];
char ambe_fr4[4][24]; //shim for crappy tdma direct, need more samples to see if this is really a necessary shim or not
char ambe_fr4[4][24];
memset (ambe_fr, 0, sizeof(ambe_fr));
memset (ambe_fr2, 0, sizeof(ambe_fr2));
memset (ambe_fr3, 0, sizeof(ambe_fr3));
//memcpy of ambe_fr for late entry
char m1[4][24];

View File

@@ -26,6 +26,14 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
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)
{
@@ -53,6 +61,14 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
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)
{
@@ -116,7 +132,7 @@ void LFSR(dsd_state * state)
void LFSR64(dsd_state * state)
{
{
uint64_t lfsr = 0;
unsigned long long int lfsr = 0;
if (state->currentslot == 0)
{
@@ -128,19 +144,16 @@ void LFSR64(dsd_state * state)
for(cnt=0;cnt<32;cnt++)
{
uint64_t bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
unsigned long long int bit = ( (lfsr >> 31) ^ (lfsr >> 21) ^ (lfsr >> 1) ^ (lfsr >> 0) ) & 0x1;
lfsr = (lfsr << 1) | bit;
}
// if (state->currentslot == 0) state->payload_miP = lfsr;
// else state->payload_miN = lfsr;
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%016lX", lfsr);
fprintf (stderr, " MI: 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_mi = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
}
@@ -150,7 +163,7 @@ void LFSR64(dsd_state * state)
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%016lX", lfsr);
fprintf (stderr, " MI: 0x%016llX", lfsr);
fprintf (stderr, "%s", KNRM);
state->payload_miR = lfsr & 0xFFFFFFFF; //truncate for next repitition and le verification
}

View File

@@ -325,15 +325,15 @@ uint8_t ComputeCrc5Bit(uint8_t * DMRData)
return CRC;
} /* End ComputeCrc5Bit() */
uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
uint64_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
{
uint32_t Output = 0;
uint64_t Output = 0;
uint32_t i;
for(i = 0; i < BitLength; i++)
{
Output <<= 1;
Output |= (uint32_t)(BufferIn[i] & 1);
Output |= (uint64_t)(BufferIn[i] & 1);
}
return Output;

View File

@@ -26,9 +26,11 @@ void closePulseOutput (dsd_opts * opts)
{
pa_simple_free (opts->pulse_digi_dev_out);
if (opts->dmr_stereo == 1)
{
pa_simple_free (opts->pulse_digi_dev_outR);
}
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);
}
void closePulseInput (dsd_opts * opts)
@@ -47,10 +49,9 @@ void openPulseOutput(dsd_opts * opts)
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
if (opts->monitor_input_audio == 1)
{
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
}
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
//tt
pa_channel_map* left = 0; //NULL and 0 are same in this context
@@ -545,6 +546,9 @@ openAudioInDevice (dsd_opts * opts)
const char ch = '.';
extension = strrchr(opts->audio_in_dev, ch); //return extension if this is a .wav or .bin file
//if no extension set, give default of .wav -- bugfix for github issue #105
// if (extension == NULL) extension = ".wav";
// get info of device/file
if (strncmp(opts->audio_in_dev, "-", 1) == 0)
{
@@ -597,7 +601,15 @@ openAudioInDevice (dsd_opts * opts)
}
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
{
#ifdef USE_RTLSDR
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)
{
@@ -607,6 +619,66 @@ openAudioInDevice (dsd_opts * opts)
{
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;

View File

@@ -217,8 +217,7 @@ invert_dibit(int dibit)
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
if ((state->synctype == 6) || (state->synctype == 14)|| (state->synctype == 18) || (state->synctype == 37))
@@ -265,30 +264,33 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) ||
(state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13) ||
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 36) )
(state->synctype == 17) || (state->synctype == 29) || (state->synctype == 31) ||
(state->synctype == 36) || (state->synctype == 99) )
{
// 1 -P25p1
// 3 -X2-TDMA (inverted signal voice frame)
// 5 -X2-TDMA (inverted signal data frame)
// 9 -NXDN (inverted voice frame)
// 9 -M17 LSR
// 11 -DMR (inverted signal voice frame)
// 13 -DMR (inverted signal data frame)
// 17 -NXDN (inverted data frame)
// 17 -M17 STR
// 29 -NXDN (inverted FSW)
// 31 -YSF
// 36 -P25p2
// 99 -M17 Preamble
int valid;
int dibit;
valid = 0;
//disabling again, causing issues with trunking P25
if (state->synctype == 1 && opts->p25_trunk == 1)
{
// Use the P25 heuristics if available
// valid = estimate_symbol(state->rf_mod, &(state->inv_p25_heuristics), state->last_dibit, symbol, &dibit);
}
//testing again, either on Voice channels only (when tuned) or with trunk disabled
if (state->synctype == 1 && (opts->p25_is_tuned == 1 || opts->p25_trunk == 0) && 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)
{
@@ -335,24 +337,26 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol)
// 0 +P25p1
// 2 +X2-TDMA (non inverted signal data 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)
// 12 +DMR (non inverted signal voice frame)
// 16 +NXDN (non inverted data frame)
// 16 +M17 STR
// 28 +NXND (FSW)
// 30 +YSF
// 35 +p25p2
// 98 +M17 Preamble
int valid;
int dibit;
valid = 0;
//disabling again, causing issues with trunking P25
if (state->synctype == 0 && opts->p25_trunk == 1)
{
// Use the P25 heuristics if available
// valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
}
//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 P25p1 heuristics if available
valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit);
}
if (valid == 0)
{

View File

@@ -34,7 +34,11 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
}
char * getDateF(void) {
char datename[80]; //32-bit needs this to be 80
#ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2;
struct tm * to;
time_t t;
@@ -530,7 +534,7 @@ void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
info.samplerate = 48000; //8000
info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info);
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_WRITE, &info);
if (opts->wav_out_raw == NULL)
{
fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw);

View File

@@ -1,8 +1,36 @@
//M17 Filter -- RRC Alpha = 0.5 S/s 48000 with 81 taps
#define M17ZEROS 80 //ONLY SEE 79 THOUGH
float m17gain = 10.0f;
static float m17xv[M17ZEROS+1];
float m17coeffs[81] =
{
-0.009265784007800534, -0.006136551625729697, -0.001125978562075172, 0.004891777252042491,
0.01071805138282269, 0.01505751553351295, 0.01679337935001369, 0.015256245142156299,
0.01042830577908502, 0.003031522725559901, -0.0055333532968188165, -0.013403099825723372,
-0.018598682349642525, -0.01944761739590459, -0.015005271935951746, -0.0053887880354343935,
0.008056525910253532, 0.022816244158307273, 0.035513467692208076, 0.04244131815783876,
0.04025481153629372, 0.02671818654865632, 0.0013810216516704976, -0.03394615682795165,
-0.07502635967975885, -0.11540977897637611, -0.14703962203941534, -0.16119995609538576,
-0.14969512896336504, -0.10610329539459686, -0.026921412469634916, 0.08757875030779196,
0.23293327870303457, 0.4006012210123992, 0.5786324696325503, 0.7528286479934068,
0.908262741447522, 1.0309661131633199, 1.1095611856548013, 1.1366197723675815,
1.1095611856548013, 1.0309661131633199, 0.908262741447522, 0.7528286479934068,
0.5786324696325503, 0.4006012210123992, 0.23293327870303457, 0.08757875030779196,
-0.026921412469634916, -0.10610329539459686, -0.14969512896336504, -0.16119995609538576,
-0.14703962203941534, -0.11540977897637611, -0.07502635967975885, -0.03394615682795165,
0.0013810216516704976, 0.02671818654865632, 0.04025481153629372, 0.04244131815783876,
0.035513467692208076, 0.022816244158307273, 0.008056525910253532, -0.0053887880354343935,
-0.015005271935951746, -0.01944761739590459, -0.018598682349642525, -0.013403099825723372,
-0.0055333532968188165, 0.003031522725559901, 0.01042830577908502, 0.015256245142156299,
0.01679337935001369, 0.01505751553351295, 0.01071805138282269, 0.004891777252042491,
-0.001125978562075172, -0.006136551625729697, -0.009265784007800534
};
// Original DMR filter
#define NZEROS 60
float ngain = 7.423339364f;
static float xv[NZEROS+1];
float xcoeffs[] =
float xcoeffs[61] =
{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f,
-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f,
+0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f,
@@ -27,7 +55,7 @@ float xcoeffs[] =
float nxgain = 15.95930463f;
static float nxv[NXZEROS+1];
float nxcoeffs[] =
float nxcoeffs[135] =
{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f,
+0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f,
-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f,
@@ -74,7 +102,7 @@ const float dmrgain = 6.82973073748f;
static float dxv[DMRNZEROS+1];
// 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.0404938748, -0.0528141756, -0.0543747957, -0.0428325003, -0.0186176083,
0.0147202645, 0.0508418571, 0.0816392577, 0.0988113688, 0.0957187780,
@@ -98,7 +126,7 @@ static float dpmrxv[NXZEROS+1];
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[] =
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,
@@ -156,6 +184,11 @@ dpmr_filter(short sample)
return dsd_input_filter(sample, 4);
}
short m17_filter (short sample)
{
return dsd_input_filter(sample, 5);
}
short
dsd_input_filter(short sample, int mode)
@@ -189,6 +222,14 @@ dsd_input_filter(short sample, int mode)
coeffs = (float *)dpmrcoeffs;
zeros = DPMRNZEROS;
break;
case 5:
gain = m17gain;
v = m17xv;
coeffs = (float *)m17coeffs;
zeros = M17ZEROS;
break;
default:
return sample;
}

View File

@@ -177,19 +177,19 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
sprintf (state->fsubtype, " VOICE ");
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
if (opts->dmr_stereo == 0 && state->synctype < 32)
{
sprintf (state->slot1light, " slot1 ");
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);
dmrMSBootstrap (opts, state);
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
}
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);
dmrMSBootstrap (opts, state);
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state);
}
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
{
@@ -198,7 +198,7 @@ processFrame (dsd_opts * opts, dsd_state * 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);
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
if (opts->p25_trunk == 0) dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
}
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
}
@@ -207,7 +207,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
dmrMSData (opts, state);
if (opts->p25_trunk == 0) dmrMSData (opts, state);
}
else
{
@@ -219,7 +219,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->err_str[0] = 0;
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
dmr_data_sync (opts, state);
}
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
@@ -231,7 +230,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
state->payload_miP = 0; //zero out when switching back to data sync
dmr_data_sync (opts, state);
}
}
@@ -290,16 +288,21 @@ processFrame (dsd_opts * opts, dsd_state * state)
//ysf
else if ((state->synctype == 30) || (state->synctype == 31))
{
//Do stuff
//fprintf(stderr, "YSF Sync! \n");
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
//openMbeOutFile (opts, state);
}
//sprintf(state->fsubtype, " VOICE ");
//relocate MBEout to inside frame handling -- Not Working Currently for YSF
processYSF(opts, state);
return;
}
//M17
else if ((state->synctype == 16) || (state->synctype == 9) || (state->synctype == 17) || (state->synctype == 8) || (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
processM17LSF(opts, state);
return;
}
//P25 P2
else if ((state->synctype == 35) || (state->synctype == 36))
{
@@ -486,10 +489,6 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->currentslot = 0;
sprintf (state->fsubtype, " LDU1 ");
state->numtdulc = 0;
if (state->payload_algid == 0x81)
{
fprintf (stderr, "\n");
}
processLDU1 (opts, state);
}
@@ -542,8 +541,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0;
state->lastsrc = 0;
// state->lasttg = 0;
// state->lastsrc = 0;
state->lastp25type = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " TDULC ");
@@ -604,10 +603,11 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
else if (strcmp (duid, "30") == 0)
{
state->dmrburstL = 29;
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," PDU\n"); //multi block/packet PDU
fprintf (stderr," MBF\n"); //multi block format PDU
}
if (opts->mbe_out_dir[0] != 0)
{
@@ -619,79 +619,11 @@ processFrame (dsd_opts * opts, dsd_state * state)
resumeScan (opts, state);
}
state->lastp25type = 4;
sprintf (state->fsubtype, " PDU ");
sprintf (state->fsubtype, " MBF ");
processMPDU(opts, state);
}
// try to guess based on previous frame if unknown type
// disabling the guessing game on P1
// 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
// 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
{
state->lastp25type = 0;
@@ -699,8 +631,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
// fprintf (stderr, "\n"); //prints on dPMR frame 3
// fprintf (stderr," duid:%s *Unknown DUID*\n", duid);
fprintf (stderr," duid:%s \n", duid); //DUID ERR
}
}
}

View File

@@ -18,39 +18,6 @@
#include "dsd.h"
#include <locale.h>
//borrowed from LEH/DSDcc for 'improved NXDN sync detection'
int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr)
{
int Compare = -1;
size_t i = 0;
int err = 0;
int BreakBeforeEnd = 0;
if(s1 && s2)
{
for(i = 0; i < size; i++)
{
if(((s1[i] & 0xFF) != '\0') && ((s2[i] & 0xFF) != '\0'))
{
if((s1[i] & 0xFF) != (s2[i] & 0xFF)) err++;
}
else
{
BreakBeforeEnd = 1;
break;
}
}
if((err <= MaxErr) && (BreakBeforeEnd == 0))
{
Compare = 0;
}
} /* End if(s1 && s2) */
return Compare;
} /* End strncmperr() */
char * getTime(void) //get pretty hh:mm:ss timestamp
{
time_t t = time(NULL);
@@ -67,7 +34,11 @@ char * getTime(void) //get pretty hh:mm:ss timestamp
}
char * getDate(void) {
char datename[32];
#ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2;
struct tm * to;
time_t t;
@@ -114,16 +85,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
* 5 = -X2-TDMA (inverted signal data frame)
* 6 = +D-STAR
* 7 = -D-STAR
* 8 = +NXDN (non inverted voice frame)
* 9 = -NXDN (inverted voice frame)
* 8 = +M17 STR (non inverted stream frame)
* 9 = -M17 STR (inverted stream frame)
* 10 = +DMR (non inverted signal data frame)
* 11 = -DMR (inverted signal voice frame)
* 12 = +DMR (non inverted signal voice frame)
* 13 = -DMR (inverted signal data frame)
* 14 = +ProVoice
* 15 = -ProVoice
* 16 = +NXDN (non inverted data frame)
* 17 = -NXDN (inverted data frame)
* 16 = +M17 LSF (non inverted link frame)
* 17 = -M17 LSF (inverted link frame)
* 18 = +D-STAR_HD
* 19 = -D-STAR_HD
* 20 = +dPMR Frame Sync 1
@@ -150,7 +121,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//start control channel hunting if using trunking, time needs updating on each successful sync
//will need to assign frequencies to a CC array for P25 since that isn't imported from CSV
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 2) ) )
if (state->dmr_rest_channel == -1 && opts->p25_is_tuned == 0 && opts->p25_trunk == 1 && ( (time(NULL) - state->last_cc_sync_time) > (opts->trunk_hangtime + 0) ) ) //was 3, go to hangtime value
{
//test to switch back to 10/4 P1 QPSK for P25 FDMA CC
@@ -163,10 +134,23 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//start going through the lcn/frequencies CC/signal hunting
fprintf (stderr, "Control Channel Signal Lost. Searching for Control Channel.\n");
//make sure our current roll value doesn't exceed value of frequencies imported
if (state->lcn_freq_roll > state->lcn_freq_count)
if (state->lcn_freq_roll >= state->lcn_freq_count) //fixed this to skip the extra wait out at the end of the list
{
state->lcn_freq_roll = 0; //reset to zero
}
//roll an extra value up if the current is the same as what's already loaded -- faster hunting on Cap+, etc
if (state->lcn_freq_roll != 0)
{
if (state->trunk_lcn_freq[state->lcn_freq_roll-1] == state->trunk_lcn_freq[state->lcn_freq_roll])
{
state->lcn_freq_roll++;
//check roll again if greater than expected, then go back to zero
if (state->lcn_freq_roll >= state->lcn_freq_count)
{
state->lcn_freq_roll = 0; //reset to zero
}
}
}
//check that we have a non zero value first, then tune next frequency
if (state->trunk_lcn_freq[state->lcn_freq_roll] != 0)
{
@@ -176,13 +160,15 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[state->lcn_freq_roll]);
}
//rtludp
//rtl
if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, state->trunk_lcn_freq[state->lcn_freq_roll]);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, state->trunk_lcn_freq[state->lcn_freq_roll]);
#endif
}
fprintf (stderr, "Tuning to Control Channel Frequency: %.06lf MHz\n",
fprintf (stderr, "Tuning to Frequency: %.06lf MHz\n",
(double)state->trunk_lcn_freq[state->lcn_freq_roll]/1000000);
}
@@ -194,12 +180,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
char synctest[25];
char synctest12[13]; //dPMR
char synctest10[11]; //NXDN FSW only
char synctest19[20]; //NXDN Preamble + FSW
char synctest18[19];
char synctest32[33];
char synctest20[21]; //YSF
char synctest21[22]; //P25 S-OEMI (SACCH)
char synctest48[49]; //EDACS
char synctest8[9]; //M17
char synctest16[17]; //M17 Preamble
char modulation[8];
char *synctest_p;
int symboltest_pos; //symbol test position, match to synctest_pos
@@ -213,19 +200,27 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
{
t_max = 10;
}
//else if dPMR
//dPMR
else if (opts->frame_dpmr == 1)
{
t_max = 12; //based on Frame_Sync_2 pattern
}
//if Phase 2 (or YSF in future), then only 20
else if (state->lastsynctype == 35 || state->lastsynctype == 36) //P2
else if (opts->frame_m17 == 1)
{
t_max = 20;
t_max = 8;
}
else if (state->lastsynctype == 30 || state->lastsynctype == 31 )
{
t_max = 20; //20 on YSF
}
//if Phase 2, then only 19
else if (state->lastsynctype == 35 || state->lastsynctype == 36 )
{
t_max = 19; //Phase 2 S-ISCH is only 19
}
else t_max = 24; //24 for everything else
int lbuf[t_max], lbuf2[t_max];
int lbuf[48], lbuf2[48]; //if we use t_max in these arrays, and t >= t_max in condition below, then it can overflow those checks in there if t exceeds t_max
int lsum;
char spectrum[64];
//init the lbuf
@@ -433,6 +428,16 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->minref = state->min;
}
//if using an rtl input method, do not look for sync patterns if the rms value is lower than our 'soft squelch' level
if (opts->audio_in_type == 3 && opts->rtl_rms < opts->rtl_squelch_level)
{
if (opts->frame_nxdn48 == 1 || opts->frame_nxdn96 == 1 || opts->frame_dpmr == 1 || opts->frame_m17 == 1)
{
goto SYNC_TEST_END;
}
}
strncpy (synctest, (synctest_p - 23), 24);
if (opts->frame_p25p1 == 1)
{
@@ -543,51 +548,138 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
}
//YSF sync
strncpy(synctest20, (synctest_p - 19), 20); //double check make sure this is right
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1
strncpy(synctest20, (synctest_p - 19), 20);
if(opts->frame_ysf == 1)
{
if (0 == 0) //opts->inverted_ysf == 0
if (strcmp(synctest20, FUSION_SYNC) == 0)
{
if (strcmp(synctest20, FUSION_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
fprintf (stderr, "\nYSF FUSION SYNC \n");
opts->inverted_ysf = 0; //should we set this here?
state->lastsynctype = 30;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (30);
}
printFrameSync (opts, state, "+YSF ", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
opts->inverted_ysf = 0;
state->lastsynctype = 30;
return (30);
}
}
if(opts->frame_ysf == 1) //(opts->frame_ysf == 1
{
if (0 == 0) //opts->inverted_ysf == 1
else if (strcmp(synctest20, INV_FUSION_SYNC) == 0)
{
if (strcmp(synctest20, INV_FUSION_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
fprintf (stderr, "\nINVERTED YSF FUSION SYNC \n");
opts->inverted_ysf = 1; //should we set this here?
state->lastsynctype = 31;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (31);
}
printFrameSync (opts, state, "-YSF ", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
opts->inverted_ysf = 1;
state->lastsynctype = 31;
return (31);
}
}
//end YSF sync
//M17 Sync -- Just STR and LSF for now
strncpy(synctest16, (synctest_p - 15), 16);
strncpy(synctest8, (synctest_p - 7), 8);
if(opts->frame_m17 == 1)
{
//preambles will skip dibits in an attempt to prime the
//demodulator but not attempt any decoding
if (strcmp(synctest8, M17_PRE) == 0)
{
if (opts->inverted_m17 == 0)
{
printFrameSync (opts, state, "+M17 PREAMBLE", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->lastsynctype = 98;
fprintf (stderr, "\n");
return (98);
}
}
else if (strcmp(synctest8, M17_PIV) == 0)
{
if (opts->inverted_m17 == 1)
{
printFrameSync (opts, state, "-M17 PREAMBLE", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->lastsynctype = 99;
fprintf (stderr, "\n");
return (99);
}
}
else if (strcmp(synctest8, M17_STR) == 0)
{
if (opts->inverted_m17 == 0)
{
printFrameSync (opts, state, "+M17 STR", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 16 || state->lastsynctype == 8)
{
state->lastsynctype = 16;
return (16);
}
state->lastsynctype = 16;
fprintf (stderr, "\n");
}
else
{
printFrameSync (opts, state, "-M17 LSF", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 99)
{
state->lastsynctype = 9;
return (9);
}
state->lastsynctype = 9;
fprintf (stderr, "\n");
}
}
else if (strcmp(synctest8, M17_LSF) == 0)
{
if (opts->inverted_m17 == 1)
{
printFrameSync (opts, state, "-M17 STR", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 17 || state->lastsynctype == 9)
{
state->lastsynctype = 17;
return (17);
}
state->lastsynctype = 17;
fprintf (stderr, "\n");
}
else
{
printFrameSync (opts, state, "+M17 LSF", synctest_pos + 1, modulation);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 98)
{
state->lastsynctype = 8;
return (8);
}
state->lastsynctype = 8;
fprintf (stderr, "\n");
}
}
}
//end M17
//P25 P2 sync S-ISCH VCH
strncpy(synctest20, (synctest_p - 19), 20);
if(opts->frame_p25p2 == 1)
@@ -618,10 +710,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " P2 Missing Parameters ");
fprintf (stderr, "%s", KNRM);
}
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (35); //35
}
@@ -657,10 +745,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
state->lastsynctype = 36; //36
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (36); //36
}
@@ -692,10 +776,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 21;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (21);
}
if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
@@ -728,10 +808,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
state->lastsynctype = 25;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (25);
}
if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
@@ -770,20 +846,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 33; //33
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33); //33
}
else //inverted MS voice frame
{
sprintf(state->ftype, "DMR MS");
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32);
}
}
@@ -810,10 +878,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 34;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (34);
}
}
@@ -839,20 +903,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (32);
}
else //inverted MS data frame
{
sprintf(state->ftype, "DMR MS");
state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (33);
}
@@ -875,10 +931,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 10;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (10);
}
@@ -895,10 +947,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 11;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (11); //11
}
@@ -920,10 +968,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (33);
}
@@ -940,10 +984,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (32);
}
@@ -965,10 +1005,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (33);
}
@@ -985,10 +1021,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (32);
}
@@ -1014,10 +1046,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 12;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (12);
}
@@ -1031,10 +1059,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 13;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (13);
}
@@ -1060,10 +1084,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (32); //treat Direct Mode same as MS mode for now
}
@@ -1100,10 +1120,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
state->firstframe = 1;
}
state->lastsynctype = 32;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (32);
}
@@ -1116,10 +1132,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 33;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
state->last_cc_sync_time = time(NULL);
return (33);
}
@@ -1130,56 +1142,61 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
//ProVoice and EDACS sync
if (opts->frame_provoice == 1)
{
strncpy (synctest32, (synctest_p - 31), 32);
strncpy (synctest48, (synctest_p - 47), 48);
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
{
strncpy (synctest32, (synctest_p - 31), 32);
strncpy (synctest48, (synctest_p - 47), 48);
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "ProVoice ");
if (opts->errorbars == 1)
printFrameSync (opts, state, "+PV ", synctest_pos + 1, modulation);
state->lastsynctype = 14;
return (14);
}
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "ProVoice ");
printFrameSync (opts, state, "-PV ", synctest_pos + 1, modulation);
state->lastsynctype = 15;
return (15);
}
else if ( strcmp (synctest48, EDACS_SYNC) == 0)
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
printFrameSync (opts, state, "-EDACS", synctest_pos + 1, modulation);
state->lastsynctype = 38;
return (38);
}
else if ( strcmp (synctest48, INV_EDACS_SYNC) == 0)
{
sprintf (state->ftype, "ProVoice ");
if (opts->errorbars == 1)
printFrameSync (opts, state, "+PV ", synctest_pos + 1, modulation);
state->lastsynctype = 14;
return (14);
}
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
printFrameSync (opts, state, "+EDACS", synctest_pos + 1, modulation);
state->lastsynctype = 37;
return (37);
}
sprintf (state->ftype, "ProVoice ");
printFrameSync (opts, state, "-PV ", synctest_pos + 1, modulation);
state->lastsynctype = 15;
return (15);
}
else if ( strcmp (synctest48, EDACS_SYNC) == 0)
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
printFrameSync (opts, state, "-EDACS", synctest_pos + 1, modulation);
state->lastsynctype = 38;
return (38);
}
else if ( strcmp (synctest48, INV_EDACS_SYNC) == 0)
{
state->last_cc_sync_time = time(NULL);
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
printFrameSync (opts, state, "+EDACS", synctest_pos + 1, modulation);
state->lastsynctype = 37;
return (37);
}
else if ((strcmp (synctest48, DOTTING_SEQUENCE_A) == 0) || (strcmp (synctest48, DOTTING_SEQUENCE_B) == 0))
{
printFrameSync (opts, state, " EDACS DOTTING SEQUENCE: ", synctest_pos + 1, modulation);
eot_cc (opts, state);
}
}
@@ -1197,11 +1214,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+D-STAR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 6;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (6);
}
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
@@ -1216,11 +1228,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-D-STAR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 7;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (7);
}
if (strcmp (synctest, DSTAR_HD) == 0)
@@ -1235,11 +1242,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "+D-STAR_HD ", synctest_pos + 1, modulation);
}
state->lastsynctype = 18;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (18);
}
if (strcmp (synctest, INV_DSTAR_HD) == 0)
@@ -1254,81 +1256,148 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
printFrameSync (opts, state, "-D-STAR_HD ", synctest_pos + 1, modulation);
}
state->lastsynctype = 19;
if ( opts->monitor_input_audio == 1)
{
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
}
return (19);
}
}
//NXDN FSW sync and handling - moved to very bottom of sync stack for falsing sanity
//NXDN
else if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
{
strncpy (synctest10, (synctest_p - 9), 10); //FSW only
strncpy (synctest19, (synctest_p - 18), 19); //Preamble + FSW
//Preamble plus FSW, proceed right away
if ( (strncmperr (synctest19, NXDN_PANDFSW, 19, 1) == 0) )
if (
(strcmp (synctest10, "3131331131") == 0 ) //this seems to be the most common 'correct' pattern on Type-C
|| (strcmp (synctest10, "3331331131") == 0 ) //this one hits on new sync but gives a bad lich code
|| (strcmp (synctest10, "3131331111") == 0 )
|| (strcmp (synctest10, "3331331111") == 0 )
|| (strcmp (synctest10, "3131311131") == 0 ) //First few FSW on NXDN48 Type-C seems to hit this for some reason
)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->lastsynctype = 28;
state->last_cc_sync_time = time(NULL);
//if (opts->payload == 1) fprintf (stderr, "PANDF ");
return (28);
}
else if ( (strncmperr (synctest19, INV_NXDN_PANDFSW, 19, 1) == 0) )
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->lastsynctype = 29;
state->last_cc_sync_time = time(NULL);
//if (opts->payload == 1) fprintf (stderr, "PANDF ");
return (29);
}
else if ( (strncmperr (synctest10, NXDN_FSW, 10, 1) == 0) )
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 28)
{
state->last_cc_sync_time = time(NULL);
//if (opts->payload == 1) fprintf (stderr, "FSW ");
return (28);
}
state->lastsynctype = 28; //need two consecutive patterns to continue
state->lastsynctype = 28;
}
else if ( (strncmperr (synctest10, INV_NXDN_FSW, 10, 1) == 0) )
else if (
(strcmp (synctest10, "1313113313") == 0 )
|| (strcmp (synctest10, "1113113313") == 0 )
|| (strcmp (synctest10, "1313113333") == 0 )
|| (strcmp (synctest10, "1113113333") == 0 )
|| (strcmp (synctest10, "1313133313") == 0 )
)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
if (state->lastsynctype == 29)
{
state->last_cc_sync_time = time(NULL);
//if (opts->payload == 1) fprintf (stderr, "FSW ");
return (29);
}
state->lastsynctype = 29; //need two consecutive patterns to continue
state->lastsynctype = 29;
}
}
//Provoice Conventional -- Some False Positives due to shortened frame sync pattern, so use squelch if possible
#ifdef PVCONVENTIONAL
if (opts->frame_provoice == 1)
{
memset (synctest32, 0, sizeof(synctest32));
strncpy (synctest32, (synctest_p - 31), 16); //short sync grab here on 32
char pvc_txs[9]; //string (symbol) value of TX Address
char pvc_rxs[9]; //string (symbol) value of RX Address
uint8_t pvc_txa = 0; //actual value of TX Address
uint8_t pvc_rxa = 0; //actual value of RX Address
strncpy (pvc_txs, (synctest_p - 15), 8); //copy string value of TX Address
strncpy (pvc_rxs, (synctest_p - 7), 8); //copy string value of RX Address
if ((strcmp (synctest32, INV_PROVOICE_CONV_SHORT) == 0))
{
if (state->lastsynctype == 15) //use this condition, like NXDN, to migitage false positives due to short sync pattern
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "ProVoice ");
// fprintf (stderr, "Sync Pattern = %s ", synctest32);
// fprintf (stderr, "TX = %s ", pvc_txs);
// fprintf (stderr, "RX = %s ", pvc_rxs);
for (int i = 0; i < 8; i++)
{
pvc_txa = pvc_txa << 1;
pvc_rxa = pvc_rxa << 1;
//symbol 1 is binary 1 on inverted
//I hate working with strings, has to be a better way to evaluate this
memset (pvc_txs, 0, sizeof (pvc_txs));
memset (pvc_rxs, 0, sizeof (pvc_rxs));
strncpy (pvc_txs, (synctest_p - 15+i), 1);
strncpy (pvc_rxs, (synctest_p - 7+i), 1);
if ((strcmp (pvc_txs, "1") == 0))
pvc_txa = pvc_txa + 1;
if ((strcmp (pvc_rxs, "1") == 0))
pvc_rxa = pvc_rxa + 1;
}
printFrameSync (opts, state, "-PV_C ", synctest_pos + 1, modulation);
fprintf (stderr, "TX: %d ", pvc_txa);
fprintf (stderr, "RX: %d ", pvc_rxa);
if (pvc_txa == 172) fprintf (stderr, "ALL CALL ");
state->lastsynctype = 15;
return (15);
}
state->lastsynctype = 15;
}
else if ((strcmp (synctest32, PROVOICE_CONV_SHORT) == 0))
{
if (state->lastsynctype == 14) //use this condition, like NXDN, to migitage false positives due to short sync pattern
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf (state->ftype, "ProVoice ");
// fprintf (stderr, "Sync Pattern = %s ", synctest32);
// fprintf (stderr, "TX = %s ", pvc_txs);
// fprintf (stderr, "RX = %s ", pvc_rxs);
for (int i = 0; i < 8; i++)
{
pvc_txa = pvc_txa << 1;
pvc_rxa = pvc_rxa << 1;
//symbol 3 is binary 1 on positive
//I hate working with strings, has to be a better way to evaluate this
memset (pvc_txs, 0, sizeof (pvc_txs));
memset (pvc_rxs, 0, sizeof (pvc_rxs));
strncpy (pvc_txs, (synctest_p - 15+i), 1);
strncpy (pvc_rxs, (synctest_p - 7+i), 1);
if ((strcmp (pvc_txs, "3") == 0))
pvc_txa = pvc_txa + 1;
if ((strcmp (pvc_rxs, "3") == 0))
pvc_rxa = pvc_rxa + 1;
}
printFrameSync (opts, state, "+PV_C ", synctest_pos + 1, modulation);
fprintf (stderr, "TX: %d ", pvc_txa);
fprintf (stderr, "RX: %d ", pvc_rxa);
if (pvc_txa == 172) fprintf (stderr, "ALL CALL ");
state->lastsynctype = 14;
return (14);
}
state->lastsynctype = 14;
}
}
#endif //End Provoice Conventional
SYNC_TEST_END: ; //do nothing
} // t >= 10
if (exitflag == 1)
@@ -1359,7 +1428,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,"Press CTRL + C to close.\n");
// fprintf (stderr,"Press CTRL + C to close.\n");
}
noCarrier (opts, state);

View File

@@ -146,7 +146,8 @@ int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
return 0;
}
int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
//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);
@@ -210,3 +211,48 @@ int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support
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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,26 +2,59 @@
#include "dsd.h"
#include "p25p1_heuristics.h"
void
resetState (dsd_state * state)
//fixed the memory leak, but now random segfaults occur -- double free or corruption (out) or (!prev)
void resetState (dsd_state * state)
{
int i, j;
//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);
state->repeat = 0; //not sure yet
//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;
//state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
//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;
//state->wav_out_bytes = 0;
state->dibit_buf_p = state->dibit_buf + 200;
memset (state->dibit_buf, 0, sizeof (int) * 200);
state->repeat = 0; //repeat frame?
//Audio Buffer -- Free Allocated Memory
free (state->audio_out_buf);
free (state->audio_out_float_buf);
free (state->audio_out_bufR);
free (state->audio_out_float_bufR);
//Audio Buffer -- Memset/Init/Allocate Memory per slot
//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->jitter = -1;
state->synctype = -1;
@@ -31,76 +64,73 @@ resetState (dsd_state * state)
state->umid = 0;
state->minref = -12000;
state->maxref = 12000;
state->lastsample = 0;
for (i = 0; i < 128; i++)
{
state->sbuf[i] = 0;
}
{
state->sbuf[i] = 0;
}
state->sidx = 0;
for (i = 0; i < 1024; i++)
{
state->maxbuf[i] = 15000;
}
{
state->maxbuf[i] = 15000;
}
for (i = 0; i < 1024; i++)
{
state->minbuf[i] = -15000;
}
{
state->minbuf[i] = -15000;
}
state->midx = 0;
state->err_str[0] = 0;
sprintf (state->fsubtype, " ");
sprintf (state->ftype, " ");
state->symbolcnt = 0;
state->rf_mod = 0;
state->numflips = 0;
state->lastsynctype = -1;
state->lastp25type = 0;
state->offset = 0;
state->carrier = 0;
for (i = 0; i < 25; i++)
{
for (j = 0; j < 16; j++)
{
state->tg[i][j] = 48;
}
}
state->tgcount = 0;
state->lasttg = 0;
state->lastsrc = 0;
state->nac = 0;
//Reset Voice Errors in C0 and C1 (or remaining Codewords in IMBE)
state->errs = 0;
state->errs2 = 0;
state->mbe_file_type = -1;
state->errsR = 0;
state->errs2R = 0;
//Misc -- may not be needed
state->optind = 0;
state->numtdulc = 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;
state->debug_header_errors = 0;
state->debug_header_critical_errors = 0;
//unsure if these are still used or ever were used,
// 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->nxdn_last_ran = 0;
// state->payload_algid = 0;
// state->payload_algidR = 0;
state->dmr_encL = 0;
state->dmr_encR = 0;
// //MBE Specific
// //free the memory before allocating it again -- may not use this
// free (state->cur_mp);
// free (state->prev_mp);
// free (state->prev_mp_enhanced);
//each time you run this, it increses memory use by 4MB, massive memory leak
//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
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
// //memory allocation and init on mbe -- may not use this
// 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);
//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);
}

View File

@@ -250,6 +250,7 @@ int UDPBind (char *hostname, int portno)
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)
{
int handle;
@@ -274,8 +275,5 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
address.sin_port = htons(udp_port);
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
//BUGFIX: This was causing an indefinite number of UDP sockets to stay open on each tune request
//we open a new socket with each request, so we need to close the socket after writing to it
//this would cause the tuning to stop after x number of tune attempts (few hours? on a busy system)
close (handle); //close socket after sending.
}

View File

@@ -17,6 +17,29 @@
#include "dsd.h"
long int raw_rms(int16_t *samples, int len, int step) //use samplespersymbol as len
{
int i;
long int rms;
long p, t, s;
double dc, err;
p = t = 0L;
for (i=0; i<len; i+=step) {
s = (long)samples[i];
t += s;
p += s * s;
}
/* correct for dc offset in squares */
dc = (double)(t*step) / (double)len;
err = t * 2 * dc - dc * dc * len;
rms = (long int)sqrt((p-err) / len);
if (rms < 0) rms = 150;
return rms;
}
int
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
{
@@ -111,7 +134,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
{
sf_close(opts->audio_in_file);
fprintf (stderr, "\n\nEnd of .wav file.\n");
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)
{
@@ -119,60 +142,216 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
openPulseInput(opts); //open pulse input
}
//else cleanup and exit
else cleanupAndExit(opts, state);
else
{
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
cleanupAndExit(opts, state);
}
}
}
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
// TODO: need to read demodulated stream here
// get_rtlsdr_sample(&sample);
// Read demodulated stream here
get_rtlsdr_sample(&sample, opts, state);
if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767)
{
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);
}
opts->rtl_rms = rtl_return_rms();
#endif
}
//tcp socket input from SDR++
//tcp socket input from SDR++ -- now with 1 retry if connection is broken
else if (opts->audio_in_type == 8)
{
#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
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
//open pulse input if we are pulse output AND using ncurses terminal
if (opts->audio_out_type == 0 && opts->use_ncurses_terminal == 1)
//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
openPulseInput(opts); //open pulse input
}
//else cleanup and exit
else cleanupAndExit(opts, state);
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");
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
cleanupAndExit(opts, state);
}
}
}
#else
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
fprintf (stderr, "Connection to TCP Server Disconnected.\n");
}
}
#endif
}
//UDP Socket input...not working correct. Reads samples, but no sync
// else if (opts->audio_in_type == 6)
// {
//I think this doesn't get the entire dgram when we run sf_read_short on the udp dgram
// result = sf_read_short(opts->udp_file_in, &sample, 1);
// if (sample != 0)
// fprintf (stderr, "Result = %d Sample = %d \n", result, sample);
// }
//Source Audio Monitoring
if (have_sync == 0)
{
//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);
//debug
// opts->rtl_rms = 101;
//make it a little quieter
// for (int x = 0; x < 960; x++)
// state->analog_out[x] /= 4;
//seems to be working now, but RMS values are lower on actual analog signal than on no signal but noise
if ( (opts->rtl_rms > opts->rtl_squelch_level) && (opts->monitor_input_audio == 1) )
{
if (opts->audio_out_type == 0)
pa_simple_write(opts->pulse_raw_dev_out, state->analog_out, 960*2, NULL);
//NOTE: Worked okay earlier in Cygwin, so should be fine
if (opts->audio_out_type == 5)
write (opts->audio_out_fd, state->analog_out, 960*2);
//test hold on scan/trunking
state->last_cc_sync_time = time(NULL);
state->last_vc_sync_time = time(NULL);
}
//raw wav file saving -- only write when not NXDN, dPMR, or M17 due to noise that can cause tons of false positives when no sync
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;
}
}
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);
}
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||
state->lastsynctype == 16 || state->lastsynctype == 17 ||
else if (state->lastsynctype == 8 || state->lastsynctype == 9 ||state->lastsynctype == 16 || state->lastsynctype == 17)
{
sample = m17_filter(sample);
}
else if (
state->lastsynctype == 20 || state->lastsynctype == 21 ||
state->lastsynctype == 22 || state->lastsynctype == 23 ||
state->lastsynctype == 24 || state->lastsynctype == 25 ||
@@ -411,7 +590,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
{
// opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted
fclose(opts->symbolfile);
fprintf (stderr, "\n\nEnd of .bin file\n");
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)
{
@@ -419,7 +598,11 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
openPulseInput(opts); //open pulse input
}
//else cleanup and exit
else cleanupAndExit(opts, state);
else
{
if (opts->use_ncurses_terminal == 1) ncursesClose(opts);
cleanupAndExit(opts, state);
}
}
//assign symbol/dibit values based on modulation type

View File

@@ -14,12 +14,16 @@
* 1994-7
*
* LWVMOBILE
* 2022-10 Version EDACS-FM Florida Man Edition
* 2023-08 Version EDACS-FM Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
char * getDateE(void) {
char datename[99]; //might honestly just need a much smaller size, and not a larger one
#ifdef AERO_BUILD
char datename[80];
#else
char datename[99];
#endif
char * curr2;
struct tm * to;
time_t t;
@@ -45,6 +49,210 @@ char * getTimeE(void) //get pretty hh:mm:ss timestamp
return curr;
}
void openWavOutFile48k (dsd_opts * opts, dsd_state * state)
{
SF_INFO info;
info.samplerate = 48000; //48k for analog output (has to match input)
info.channels = 1;
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info);
if (opts->wav_out_f == NULL)
{
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
return;
}
}
//generic rms type function
long int gen_rms(short *samples, int len, int step)
{
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);
//make sure it doesnt' randomly feed us a large negative value (overflow?)
if (rms < 0) rms = 150; //could also consider returning 0 and making it return the last known good value instead
return rms;
}
//listening to and playing back analog audio
void edacs_analog(dsd_opts * opts, dsd_state * state, int afs, unsigned char lcn)
{
int i;
short analog1[960];
short analog2[960];
short analog3[960];
short sample = 0;
state->last_cc_sync_time = time(NULL);
state->last_vc_sync_time = time(NULL);
memset (analog1, 0, sizeof(analog1));
memset (analog2, 0, sizeof(analog2));
memset (analog3, 0, sizeof(analog3));
long int rms = opts->rtl_squelch_level + 1; //one more for the initial loop phase
long int sql = opts->rtl_squelch_level;
fprintf (stderr, "\n");
while (rms > sql) //!exitflag && -- no exitflag on this version
{
//this will only work on 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 );
analog1[i] = sample;
}
for (i = 0; i < 960; i++)
{
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
analog2[i] = sample;
}
for (i = 0; i < 960; i++)
{
pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL );
analog3[i] = sample;
}
//this rms will only work properly (for now) with squelch enabled in SDR++ or other
rms = gen_rms(analog3, 960, 1);
}
//TCP Input -- TODO: Error Handling if connection drops
if (opts->audio_in_type == 8)
{
for (i = 0; i < 960; i++)
{
sf_read_short(opts->tcp_file_in, &sample, 1);
analog1[i] = sample;
}
for (i = 0; i < 960; i++)
{
sf_read_short(opts->tcp_file_in, &sample, 1);
analog2[i] = sample;
}
for (i = 0; i < 960; i++)
{
sf_read_short(opts->tcp_file_in, &sample, 1);
analog3[i] = sample;
}
//this rms will only work properly (for now) with squelch enabled in SDR++
rms = gen_rms(analog3, 960, 1);
}
//RTL Input
#ifdef USE_RTLSDR
if (opts->audio_in_type == 3)
{
for (i = 0; i < 960; i++)
{
get_rtlsdr_sample(&sample, opts, state);
analog1[i] = sample;
}
for (i = 0; i < 960; i++)
{
get_rtlsdr_sample(&sample, opts, state);
analog2[i] = sample;
}
for (i = 0; i < 960; i++)
{
get_rtlsdr_sample(&sample, opts, state);
analog3[i] = sample;
}
//the rtl rms value works properly without needing a 'hard' squelch value
rms = rtl_return_rms();
}
#endif
if (opts->audio_out_type == 0)
{
pa_simple_write(opts->pulse_raw_dev_out, analog1, 960*2, NULL);
pa_simple_write(opts->pulse_raw_dev_out, analog2, 960*2, NULL);
pa_simple_write(opts->pulse_raw_dev_out, analog3, 960*2, NULL);
}
if (opts->audio_out_type == 5)
{
write (opts->audio_out_fd, analog1, 960*2);
write (opts->audio_out_fd, analog2, 960*2);
write (opts->audio_out_fd, analog3, 960*2);
}
opts->rtl_rms = rms;
printFrameSync (opts, state, " EDACS", 0, "A");
if (rms < sql) fprintf (stderr, "%s", KRED);
else fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Analog RMS: %04ld SQL: %ld", rms, sql);
if (afs != 0)
fprintf (stderr, " AFS [0x%03X] [%02d-%03d] LCN [%02d]", afs, afs >> 7, afs & 0x7F, lcn);
fprintf (stderr, "%s", KNRM);
//Update Ncurses Terminal
if (opts->use_ncurses_terminal == 1)
ncursesPrinter(opts, state);
//WIP: Write Analog Samples to wav file, easy enough,
//but needs wav to be opened as 48k, or downsampled
//working on 48k version of openWavOutFile
if (opts->wav_out_f != NULL)
{
sf_write_short(opts->wav_out_f, analog1, 960);
sf_write_short(opts->wav_out_f, analog2, 960);
sf_write_short(opts->wav_out_f, analog3, 960);
}
//digitize analog samples for a dotting sequence check
unsigned long long int sr = 0;
for (i = 0; i < 960; i+=5) //Samples Per Symbol is 5, so incrememnt every 5
{
sr = sr << 1;
sr += digitize (opts, state, (int)analog1[i]);
}
//debug
// fprintf (stderr, " SR: %016llX", sr);
if (sr == 0xAAAAAAAAAAAAAAAA || sr == 0x5555555555555555)
{
fprintf (stderr, " EDACS DOTTING SEQUENCE: ");
rms = 0; //break while loop by dropping rms value
fprintf (stderr, "\n");
}
if (rms > sql) fprintf (stderr, "\n");
}
}
void edacs(dsd_opts * opts, dsd_state * state)
{
//changed to ulli here for 32-bit cygwin (not sure if was an issue, but playing it safe)
@@ -64,7 +272,6 @@ void edacs(dsd_opts * opts, dsd_state * state)
unsigned char command = 0xFF;
unsigned char mt1 = 0x1F;
unsigned char mt2 = 0xF;
unsigned char mta = 0;
unsigned char lcn = 0;
//commands; may not use these anymore
@@ -75,7 +282,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
state->edacs_vc_lcn = -1; //init on negative for ncurses and tuning
int i, j;
int i;
int edacs_bit[241] = {0}; //zero out bit array and collect bits into it.
for (i = 0; i < 240; i++) //288 bits every transmission minus 48 bit (24 dibit) sync pattern
@@ -124,32 +331,32 @@ void edacs(dsd_opts * opts, dsd_state * state)
{
//ESK on/off detection, I honestly don't remember the logic for this anymore, but it works fine
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
{
if ( (((fr_1t & 0xF000000000) >> 36) != 0xB) && (((fr_1t & 0xF000000000) >> 36) != 0x1) && (((fr_1t & 0xFF00000000) >> 32) != 0xF3) )
{
//experimenting with values here, not too high, and not too low
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
if ( (((fr_1t & 0xF000000000) >> 36) <= 0x8 ))
{
state->esk_mask = 0xA0;
state->esk_mask = 0xA0;
}
//ideal value would be 5, but some other values exist that don't allow it
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
if ( (((fr_1t & 0xF000000000) >> 36) > 0x8 ) )
{
state->esk_mask = 0x0;
state->esk_mask = 0x0;
}
}
}
//Standard/Networked Auto Detection
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
//if (command == netcmd) //netcmd is F3 Standard/Networked (I think)
if ( (fr_1t >> 32 == netcmd) || (fr_1t >> 32 == (netcmd ^ 0xA0)) )
{
state->ea_mode = 0; //disable extended addressing mode
}
state->ea_mode = 0; //disable extended addressing mode
}
//EA Auto detection //peercmd is 0xF88 peer site relay 0xFF80000000 >> 28
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
if (fr_1t >> 28 == peercmd || fr_1t >> 28 == (peercmd ^ 0xA00) )
{
state->ea_mode = 1; //enable extended addressing mode
}
state->ea_mode = 1; //enable extended addressing mode
}
//Start Extended Addressing Mode
if (state->ea_mode == 1)
@@ -255,6 +462,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
fprintf (stderr, " Group [%05d] Source [%08d] LCN[%02d]", group, source, lcn);
char mode[8]; //allow, block, digital enc
sprintf (mode, "%s", "");
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
@@ -266,6 +474,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -284,6 +493,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
{
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld TG %d SRC %d.wav", getDateE(), getTimeE(), state->edacs_site_id, group, source);
openWavOutFile (opts, state);
// openWavOutFile48k (opts, state); //debug for testing analog wav only
}
//do condition here, in future, will allow us to use tuning methods as well, or rtl_udp as well
@@ -292,15 +502,20 @@ void edacs(dsd_opts * opts, dsd_state * state)
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because the lcn index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
opts->p25_is_tuned = 1;
//debug testing (since I don't have EDACS standard w/ Analog nearby)
// edacs_analog(opts, state, group, lcn);
}
if (opts->audio_in_type == 3) //rtl dongle
{
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
opts->p25_is_tuned = 1;
//debug testing (since I don't have EDACS standard w/ Analog nearby)
// edacs_analog(opts, state, group, lcn);
#endif
}
}
@@ -384,6 +599,7 @@ void edacs(dsd_opts * opts, dsd_state * state)
fprintf (stderr, " AFS [0x%03X] [%02d-%03d] LCN [%02d]", afs, a, fs, lcn);
char mode[8]; //allow, block, digital enc
sprintf (mode, "%s", "");
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
@@ -395,47 +611,61 @@ void edacs(dsd_opts * opts, dsd_state * state)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//NOTE: Restructured below so that analog and digital are handled the same, just that when
//its analog, it will now start edacs_analog which will while loop analog samples until
//signal level drops (RMS, or a dotting sequence is detected)
//analog working now with edacs_analog
if (command == 0xEE)
{
//no handling for raw audio yet...that works properly atleast
fprintf (stderr, " Analog");
}
else //Digital Call (ProVoice, hopefully not Aegis in 2022)
{
//Digital Call (ProVoice, hopefully, and not Aegis in 2022)
else
fprintf (stderr, " Digital");
//this is working now with the new import setup
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
//skip analog calls on RTL Input on ARM devices due to High CPU usage from RTL RMS function
#ifdef __arm__
if (command == 0xEE && opts->audio_in_type == 3)
goto ENDPV;
#endif
//this is working now with the new import setup
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0) ) //DE is digital encrypted, B is block
{
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
{
if (lcn < 26 && state->trunk_lcn_freq[lcn-1] != 0) //don't tune if zero (not loaded or otherwise)
//openwav file and do per call right here
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
{
//openwav file and do per call right here
if (opts->dmr_stereo_wav == 1 && (opts->use_rigctl == 1 || opts->audio_in_type == 3))
{
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %X.wav", getDateE(), getTimeE(), state->edacs_site_id, afs);
openWavOutFile (opts, state);
}
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
}
if (opts->audio_in_type == 3) //rtl dongle
{
rtl_udp_tune(opts, state, state->trunk_lcn_freq[lcn-1]);
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
}
sprintf (opts->wav_out_file, "./WAV/%s %s pV Site %lld AFS %02d-%03d - %X.wav", getDateE(), getTimeE(), state->edacs_site_id, a, fs, afs);
if (command == 0xEF) openWavOutFile (opts, state); //digital
if (command == 0xEE) openWavOutFile48k (opts, state); //analog at 48k
}
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_lcn_freq[lcn-1]); //minus one because our index starts at zero
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
}
if (opts->audio_in_type == 3) //rtl dongle
{
#ifdef USE_RTLSDR
rtl_dev_tune (opts, state->trunk_lcn_freq[lcn-1]);
state->edacs_tuned_lcn = lcn;
opts->p25_is_tuned = 1;
if (command == 0xEE) edacs_analog(opts, state, afs, lcn);
#endif
}
}
}
fprintf (stderr, "%s", KNRM);
}
@@ -456,10 +686,63 @@ void edacs(dsd_opts * opts, dsd_state * state)
} //end Standard or Networked
}
}
ENDPV:
fprintf (stderr, "\n");
}
void eot_cc(dsd_opts * opts, dsd_state * state)
{
fprintf (stderr, "EOT; \n");
//jump back to CC here
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
{
//rigctl
if (opts->use_rigctl == 1)
{
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
}
//rtl
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
rtl_dev_tune (opts, state->p25_cc_freq);
#endif
}
}
}

View File

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

809
src/m17.c Normal file
View File

@@ -0,0 +1,809 @@
/*-------------------------------------------------------------------------------
* m17.c
* M17 Decoder (WIP)
*
* m17_scramble Bit Array from SDR++
* CRC16 from M17-Implementations (thanks again, sp5wwp)
*
* LWVMOBILE
* 2023-07 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
//try to find a fancy lfsr or calculation for this and not an array if possible
uint8_t m17_scramble[369] = {
1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1,
1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,
0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1,
1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1,
0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0,
1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0,
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1,
1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,
0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1
};
char b40[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/.";
uint8_t p1[62] = {
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1
};
//produce 6 short samples (48k) for every 1 short sample (8k)
void upsampleM17 (short invalue, short prev, short outbuf[6])
{
float c, d;
c = prev;
d = invalue;
// basic triangle interpolation
outbuf[0] = c = ((invalue * (float) 0.166) + (c * (float) 0.834));
outbuf[1] = c = ((invalue * (float) 0.332) + (c * (float) 0.668));
outbuf[2] = c = ((invalue * (float) 0.500) + (c * (float) 0.5));
outbuf[3] = c = ((invalue * (float) 0.668) + (c * (float) 0.332));
outbuf[4] = c = ((invalue * (float) 0.834) + (c * (float) 0.166));
outbuf[5] = c = d;
prev = d; //shift prev to the last d value for the next repitition
}
//from M17_Implementations -- sp5wwp -- should have just looked here to begin with
//this setup looks very similar to the OP25 variant of crc16, but with a few differences (uses packed bytes)
uint16_t crc16m17(const uint8_t *in, const uint16_t len)
{
uint32_t crc = 0xFFFF; //init val
uint16_t poly = 0x5935;
for(uint16_t i=0; i<len; i++)
{
crc^=in[i]<<8;
for(uint8_t j=0; j<8; j++)
{
crc<<=1;
if(crc&0x10000)
crc=(crc^poly)&0xFFFF;
}
}
return crc&(0xFFFF);
}
void M17decodeCSD(dsd_state * state, unsigned long long int dst, unsigned long long int src)
{
//evaluate dst and src, and determine if they need to be converted to calsign
int i, j;
char c;
unsigned long long int value;
if (dst == 0xFFFFFFFFFFFF)
fprintf (stderr, " DST: BROADCAST");
else if (dst == 0)
fprintf (stderr, " DST: RESERVED %012llx", dst);
else if (dst >= 0xEE6B28000000)
fprintf (stderr, " DST: RESERVED %012llx", dst);
else
{
fprintf (stderr, " DST: ");
for (i = 0; i < 9; i++)
{
c = b40[dst % 40];
state->m17_dst_csd[i] = c;
fprintf (stderr, "%c", c);
dst = dst / 40;
}
//assign completed CSD to a more useful string instead
sprintf (state->m17_dst_str, "%c%c%c%c%c%c%c%c%c",
state->m17_dst_csd[0], state->m17_dst_csd[1], state->m17_dst_csd[2], state->m17_dst_csd[3],
state->m17_dst_csd[4], state->m17_dst_csd[5], state->m17_dst_csd[6], state->m17_dst_csd[7], state->m17_dst_csd[8]);
//debug
// fprintf (stderr, "DT: %s", state->m17_dst_str);
}
if (src == 0xFFFFFFFFFFFF)
fprintf (stderr, " SRC: UNKNOWN FFFFFFFFFFFF");
else if (src == 0)
fprintf (stderr, " SRC: RESERVED %012llx", src);
else if (src >= 0xEE6B28000000)
fprintf (stderr, " SRC: RESERVED %012llx", src);
else
{
fprintf (stderr, " SRC: ");
for (i = 0; i < 9; i++)
{
c = b40[src % 40];
state->m17_src_csd[i] = c;
fprintf (stderr, "%c", c);
src = src / 40;
}
//assign completed CSD to a more useful string instead
sprintf (state->m17_src_str, "%c%c%c%c%c%c%c%c%c",
state->m17_src_csd[0], state->m17_src_csd[1], state->m17_src_csd[2], state->m17_src_csd[3],
state->m17_src_csd[4], state->m17_src_csd[5], state->m17_src_csd[6], state->m17_src_csd[7], state->m17_src_csd[8]);
//debug
// fprintf (stderr, "ST: %s", state->m17_src_str);
}
//debug
// fprintf (stderr, " DST: %012llX SRC: %012llX", state->m17_dst, state->m17_src);
}
void M17decodeLSF(dsd_state * state)
{
int i;
unsigned long long int lsf_dst = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[0], 48);
unsigned long long int lsf_src = (unsigned long long int)ConvertBitIntoBytes(&state->m17_lsf[48], 48);
uint16_t lsf_type = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[96], 16);
//this is the way the manual/code expects you to read these bits
// uint8_t lsf_ps = (lsf_type >> 0) & 0x1;
uint8_t lsf_dt = (lsf_type >> 1) & 0x3;
uint8_t lsf_et = (lsf_type >> 3) & 0x3;
uint8_t lsf_es = (lsf_type >> 5) & 0x3;
uint8_t lsf_cn = (lsf_type >> 7) & 0xF;
uint8_t lsf_rs = (lsf_type >> 11) & 0x1F;
//store this so we can reference it for playing voice and/or decoding data, dst/src etc
state->m17_str_dt = lsf_dt;
state->m17_dst = lsf_dst;
state->m17_src = lsf_src;
state->m17_can = lsf_cn;
fprintf (stderr, "\n");
//packet or stream
// if (lsf_ps == 0) fprintf (stderr, " P-");
// if (lsf_ps == 1) fprintf (stderr, " S-");
fprintf (stderr, " CAN: %d", lsf_cn);
M17decodeCSD(state, lsf_dst, lsf_src);
if (lsf_dt == 0) fprintf (stderr, " Reserved");
if (lsf_dt == 1) fprintf (stderr, " Data");
if (lsf_dt == 2) fprintf (stderr, " Voice (3200bps)");
if (lsf_dt == 3) fprintf (stderr, " Voice + Data");
if (lsf_rs != 0) fprintf (stderr, " RS: %02X", lsf_rs);
if (lsf_et != 0) fprintf (stderr, " ENC:");
if (lsf_et == 2) fprintf (stderr, " AES-CTR");
if (lsf_et == 1) fprintf (stderr, " Scrambler - %d", lsf_es);
state->m17_enc = lsf_et;
state->m17_enc_st = lsf_es;
//pack meta bits into 14 bytes
for (i = 0; i < 14; i++)
state->m17_meta[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[(i*8)+112], 8);
//Examine the Meta data
if (lsf_et == 0 && state->m17_meta[0] != 0) //not sure if this applies universally, or just to text data byte 0 for null data
{
fprintf (stderr, " Meta:");
if (lsf_es == 0) fprintf (stderr, " Text Data");
if (lsf_es == 1) fprintf (stderr, " GNSS Pos");
if (lsf_es == 2) fprintf (stderr, " Extended CSD");
if (lsf_es == 3) fprintf (stderr, " Reserved");
}
if (lsf_et == 2)
{
fprintf (stderr, " IV: ");
for (i = 0; i < 16; i++)
fprintf (stderr, "%02X", state->m17_meta[i]);
}
}
int M17processLICH(dsd_state * state, dsd_opts * opts, uint8_t * lich_bits)
{
int i, j, err;
err = 0;
uint8_t lich[4][24];
uint8_t lich_decoded[48];
uint8_t temp[96];
bool g[4];
//for testing bit arrangement vs the crc code
uint8_t bs[240];
memset(bs, 1, sizeof(bs));
uint16_t crc_cmp = 0;
uint16_t crc_ext = 0;
uint8_t crc_err = 0;
memset(lich, 0, sizeof(lich));
memset(lich_decoded, 0, sizeof(lich_decoded));
memset(temp, 0, sizeof(temp));
//execute golay 24,12 or 4 24-bit chunks and reorder into 4 12-bit chunks
for (i = 0; i < 4; i++)
{
g[i] = TRUE;
for (j = 0; j < 24; j++)
lich[i][j] = lich_bits[(i*24)+j];
g[i] = Golay_24_12_decode(lich[i]);
if(g[i] == FALSE) err = -1;
for (j = 0; j < 12; j++)
lich_decoded[i*12+j] = lich[i][j];
}
uint8_t lich_counter = (uint8_t)ConvertBitIntoBytes(&lich_decoded[40], 3); //lich_cunt
uint8_t lich_reserve = (uint8_t)ConvertBitIntoBytes(&lich_decoded[43], 5); //lich_reserved
if (err == 0)
fprintf (stderr, "LC: %d/6 ", lich_counter+1);
else fprintf (stderr, "LICH G24 ERR");
if (err = 0 && lich_reserve != 0) fprintf(stderr, " LRS: %d", lich_reserve);
//transfer to storage
for (i = 0; i < 40; i++)
state->m17_lsf[lich_counter*40+i] = lich_decoded[i];
if (opts->payload == 1)
{
fprintf (stderr, " LICH: ");
for (i = 0; i < 6; i++)
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&lich_decoded[i*8], 8));
}
uint8_t lsf_packed[30];
memset (lsf_packed, 0, sizeof(lsf_packed));
if (lich_counter == 5)
{
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
for (i = 0; i < 30; i++)
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
crc_cmp = crc16m17(lsf_packed, 28);
crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
if (crc_cmp != crc_ext) crc_err = 1;
if (crc_err == 0)
M17decodeLSF(state);
if (opts->payload == 1)
{
fprintf (stderr, "\n LSF: ");
for (i = 0; i < 30; i++)
{
if (i == 15) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", lsf_packed[i]);
}
}
memset (state->m17_lsf, 1, sizeof(state->m17_lsf));
//debug
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
if (crc_err == 1) fprintf (stderr, " EMB LSF CRC ERR");
}
return err;
}
void M17processCodec2_1600(dsd_opts * opts, dsd_state * state, uint8_t * payload)
{
int i;
unsigned char voice1[8];
unsigned char voice2[8];
for (i = 0; i < 8; i++)
{
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
}
//TODO: Add some decryption methods
if (state->m17_enc != 0)
{
//process scrambler or AES-CTR decryption
//(no AES-CTR right now, Scrambler should be easy enough)
}
if (opts->payload == 1)
{
fprintf (stderr, "\n CODEC2: ");
for (i = 0; i < 8; i++)
fprintf (stderr, "%02X", voice1[i]);
fprintf (stderr, " (1600)");
fprintf (stderr, "\n LSDATA: "); //low speed data
for (i = 0; i < 8; i++)
fprintf (stderr, "%02X", voice2[i]);
}
#ifdef USE_CODEC2
size_t nsam;
nsam = 160;
//converted to using allocated memory pointers to prevent the overflow issues
short * samp1 = malloc (sizeof(short) * nsam);
short * upsamp = malloc (sizeof(short) * nsam * 6);
short * out = malloc (sizeof(short) * 6);
short prev;
int j;
codec2_decode(state->codec2_1600, samp1, voice1);
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
{
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
}
#ifdef AERO_BUILD
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
{
//upsample to 48k and then play
prev = samp1[0];
for (i = 0; i < 160; i++)
{
upsampleM17 (samp1[i], prev, out);
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
}
write (opts->audio_out_fd, upsamp, nsam*2*6);
}
#else
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
{
write (opts->audio_out_fd, samp1, nsam*2);
}
#endif
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
{
sf_write_short(opts->wav_out_f, samp1, nsam);
}
//TODO: Codec2 Raw file saving
// if(mbe_out_dir)
// {
// }
free (samp1);
free (upsamp);
free (out);
#endif
}
void M17processCodec2_3200(dsd_opts * opts, dsd_state * state, uint8_t * payload)
{
int i;
unsigned char voice1[8];
unsigned char voice2[8];
for (i = 0; i < 8; i++)
{
voice1[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+0], 8);
voice2[i] = (unsigned char)ConvertBitIntoBytes(&payload[i*8+64], 8);
}
//TODO: Add some decryption methods
if (state->m17_enc != 0)
{
//process scrambler or AES-CTR decryption
//(no AES-CTR right now, Scrambler should be easy enough)
}
if (opts->payload == 1)
{
fprintf (stderr, "\n CODEC2: ");
for (i = 0; i < 8; i++)
fprintf (stderr, "%02X", voice1[i]);
fprintf (stderr, " (3200)");
fprintf (stderr, "\n CODEC2: ");
for (i = 0; i < 8; i++)
fprintf (stderr, "%02X", voice2[i]);
fprintf (stderr, " (3200)");
}
#ifdef USE_CODEC2
size_t nsam;
nsam = 160;
//converted to using allocated memory pointers to prevent the overflow issues
short * samp1 = malloc (sizeof(short) * nsam);
short * samp2 = malloc (sizeof(short) * nsam);
short * upsamp = malloc (sizeof(short) * nsam * 6);
short * out = malloc (sizeof(short) * 6);
short prev;
int j;
codec2_decode(state->codec2_3200, samp1, voice1);
codec2_decode(state->codec2_3200, samp2, voice2);
if (opts->audio_out_type == 0 && state->m17_enc == 0) //Pulse Audio
{
pa_simple_write(opts->pulse_digi_dev_out, samp1, nsam*2, NULL);
pa_simple_write(opts->pulse_digi_dev_out, samp2, nsam*2, NULL);
}
#ifdef AERO_BUILD
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS w/ required upsample to 48k
{
//upsample to 48k and then play
// prev = samp1[0];
prev = 0;
for (i = 0; i < 160; i++)
{
upsampleM17 (samp1[i], prev, out);
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
}
write (opts->audio_out_fd, upsamp, nsam*2*6);
prev = samp2[0];
for (i = 0; i < 160; i++)
{
upsampleM17 (samp2[i], prev, out);
for (j = 0; j < 6; j++) upsamp[(i*6)+j] = out[j];
}
write (opts->audio_out_fd, upsamp, nsam*2*6);
}
#else
if (opts->audio_out_type == 5 && state->m17_enc == 0) //OSS via PADSP at 8k
{
write (opts->audio_out_fd, samp1, nsam*2);
write (opts->audio_out_fd, samp2, nsam*2);
}
#endif
if (opts->audio_out_type == 1 && state->m17_enc == 0) //STDOUT
{
write (opts->audio_out_fd, samp1, nsam*2);
write (opts->audio_out_fd, samp2, nsam*2);
}
//WIP: Wav file saving -- still need a way to open/close/label wav files similar to call history
if(opts->wav_out_f != NULL && state->m17_enc == 0) //WAV
{
sf_write_short(opts->wav_out_f, samp1, nsam);
sf_write_short(opts->wav_out_f, samp2, nsam);
}
//TODO: Codec2 Raw file saving
// if(mbe_out_dir)
// {
// }
free (samp1);
free (samp2);
free (upsamp);
free (out);
#endif
}
void M17prepareStream(dsd_opts * opts, dsd_state * state, uint8_t * m17_bits)
{
int i, k, x;
uint8_t m17_punc[275]; //25 * 11 = 275
memset (m17_punc, 0, sizeof(m17_punc));
for (i = 0; i < 272; i++)
m17_punc[i] = m17_bits[i+96];
//depuncture the bits
uint8_t m17_depunc[300]; //25 * 12 = 300
memset (m17_depunc, 0, sizeof(m17_depunc));
k = 0; x = 0;
for (i = 0; i < 25; i++)
{
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = m17_punc[x++];
m17_depunc[k++] = 0;
}
//setup the convolutional decoder
uint8_t temp[300];
uint8_t s0;
uint8_t s1;
uint8_t m_data[28];
uint8_t trellis_buf[144];
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (i = 0; i < 296; i++)
temp[i] = m17_depunc[i] << 1;
CNXDNConvolution_start();
for (i = 0; i < 148; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 144);
//144/8 = 18, last 4 (144-148) are trailing zeroes
for(i = 0; i < 18; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
//load m_data into bits for either data packets or voice packets
uint8_t payload[128];
uint8_t end = 9;
uint16_t fn = 0;
memset (payload, 0, sizeof(payload));
end = trellis_buf[0];
fn = (uint16_t)ConvertBitIntoBytes(&trellis_buf[1], 15);
//insert fn bits into meta 14 and meta 15 for Initialization Vector
state->m17_meta[14] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[1], 7);
state->m17_meta[15] = (uint8_t)ConvertBitIntoBytes(&trellis_buf[8], 8);
if (opts->payload == 1)
fprintf (stderr, " FSN: %05d", fn);
if (end == 1)
fprintf (stderr, " END;");
for (i = 0; i < 128; i++)
payload[i] = trellis_buf[i+16];
if (state->m17_str_dt == 2)
M17processCodec2_3200(opts, state, payload);
else if (state->m17_str_dt == 3)
M17processCodec2_1600(opts, state, payload);
else if (state->m17_str_dt == 1) fprintf (stderr, " DATA;");
else if (state->m17_str_dt == 0) fprintf (stderr, " RES;");
// else fprintf (stderr, " UNK;");
if (opts->payload == 1 && state->m17_str_dt < 2)
{
fprintf (stderr, "\n STREAM: ");
for (i = 0; i < 18; i++)
fprintf (stderr, "[%02X]", (uint8_t)ConvertBitIntoBytes(&trellis_buf[i*8], 8));
}
}
void processM17STR(dsd_opts * opts, dsd_state * state)
{
int i, x;
//overflow/memory issue returns in Cygwin for...reasons...
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
uint8_t m17_rnd_bits[368]; //368 bits that are still scrambled (randomized)
uint8_t m17_int_bits[368]; //368 bits that are still interleaved
uint8_t m17_bits[368]; //368 bits that have been de-interleaved and de-scramble
uint8_t lich_bits[96];
int lich_err = -1;
memset (dbuf, 0, sizeof(dbuf));
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
memset (m17_int_bits, 0, sizeof(m17_int_bits));
memset (m17_bits, 0, sizeof(m17_bits));
memset (lich_bits, 0, sizeof(lich_bits));
//load dibits into dibit buffer
for (i = 0; i < 184; i++)
dbuf[i] = (uint8_t) getDibit(opts, state);
//convert dbuf into a bit array
for (i = 0; i < 184; i++)
{
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
}
//descramble the frame
for (i = 0; i < 368; i++)
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
//deinterleave the bit array using Quadratic Permutation Polynomial
//function π(x) = (45x + 92x^2 ) mod 368
for (i = 0; i < 368; i++)
{
x = ((45*i)+(92*i*i)) % 368;
m17_bits[i] = m17_int_bits[x];
}
for (i = 0; i < 96; i++)
lich_bits[i] = m17_bits[i];
//check lich first, and handle LSF chunk and completed LSF
lich_err = M17processLICH(state, opts, lich_bits);
if (lich_err == 0)
M17prepareStream(opts, state, m17_bits);
// if (lich_err != 0) state->lastsynctype = -1; //disable
//ending linebreak
fprintf (stderr, "\n");
} //end processM17STR
void processM17LSF(dsd_opts * opts, dsd_state * state)
{
//NOTE: Have not been able to get this to work successfully, but considering
//there is only one LSF frame at the beginning of TX, its probably just as easy to
//use and rely on the STR frame and embedded LSF chunk, which does work properly
int i, j, k, x;
uint8_t dbuf[384]; //384-bit frame - 16-bit (8 symbol) sync pattern (184 dibits)
uint8_t m17_rnd_bits[500]; //368 bits that are still scrambled (randomized)
uint8_t m17_int_bits[500]; //368 bits that are still interleaved
uint8_t m17_bits[500]; //368 bits that have been de-interleaved and de-scramble
uint8_t m17_depunc[500]; //488 bits after depuncturing
memset (dbuf, 0, sizeof(dbuf));
memset (m17_rnd_bits, 0, sizeof(m17_rnd_bits));
memset (m17_int_bits, 0, sizeof(m17_int_bits));
memset (m17_bits, 0, sizeof(m17_bits));
memset (m17_depunc, 0, sizeof(m17_depunc));
//load dibits into dibit buffer
for (i = 0; i < 184; i++)
dbuf[i] = (uint8_t) getDibit(opts, state);
//convert dbuf into a bit array
for (i = 0; i < 184; i++)
{
m17_rnd_bits[i*2+0] = (dbuf[i] >> 1) & 1;
m17_rnd_bits[i*2+1] = (dbuf[i] >> 0) & 1;
}
//descramble the frame
for (i = 0; i < 368; i++)
m17_int_bits[i] = (m17_rnd_bits[i] ^ m17_scramble[i]) & 1;
//deinterleave the bit array using Quadratic Permutation Polynomial
//function π(x) = (45x + 92x^2 ) mod 368
for (i = 0; i < 368; i++)
{
x = ((45*i)+(92*i*i)) % 368;
m17_bits[i] = m17_int_bits[x];
}
j = 0; k = 0; x = 0;
// P1 Depuncture
for (i = 0; i < 488; i++)
{
if (p1[k++] == 1) m17_depunc[x++] = m17_bits[j++];
else m17_depunc[x++] = 1;
if (k == 61) k = 0; //61 -- should reset 8 times againt the array
}
//debug -- values seem okay at end of run
// fprintf (stderr, "K = %d; J = %d; X = %d", k, j, x);
//setup the convolutional decoder
uint8_t temp[500];
uint8_t s0;
uint8_t s1;
uint8_t m_data[30];
uint8_t trellis_buf[240]; //30*8 = 240
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (i = 0; i < 488; i++)
temp[i] = m17_depunc[i] << 1;
CNXDNConvolution_start();
for (i = 0; i < 244; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 240);
//244/8 = 30, last 4 (244-248) are trailing zeroes
for(i = 0; i < 30; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
memset (state->m17_lsf, 0, sizeof(state->m17_lsf));
memcpy (state->m17_lsf, trellis_buf, 240);
uint8_t lsf_packed[30];
memset (lsf_packed, 0, sizeof(lsf_packed));
//need to pack bytes for the sw5wwp variant of the crc (might as well, may be useful in the future)
for (i = 0; i < 30; i++)
lsf_packed[i] = (uint8_t)ConvertBitIntoBytes(&state->m17_lsf[i*8], 8);
uint16_t crc_cmp = crc16m17(lsf_packed, 28);
uint16_t crc_ext = (uint16_t)ConvertBitIntoBytes(&state->m17_lsf[224], 16);
int crc_err = 0;
if (crc_cmp != crc_ext) crc_err = 1;
if (crc_err == 0)
M17decodeLSF(state);
if (opts->payload == 1)
{
fprintf (stderr, "\n LSF: ");
for (i = 0; i < 30; i++)
{
if (i == 15) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", lsf_packed[i]);
}
}
//debug
// fprintf (stderr, " E-%04X; C-%04X (CRC CHK)", crc_ext, crc_cmp);
if (crc_err == 1) fprintf (stderr, " CRC ERR");
//ending linebreak
fprintf (stderr, "\n");
} //end processM17LSF

View File

@@ -36,27 +36,27 @@
/* 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 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_TABLE2[] = {0U, 2U, 2U, 0U, 0U, 2U, 2U, 0U};
static const uint8_t CNXDNConvolution_BRANCH_TABLE1[8] = {0U, 0U, 0U, 0U, 2U, 2U, 2U, 2U};
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 = 16U;
static const uint32_t CNXDNConvolution_M = 4U;
static const unsigned int CNXDNConvolution_K = 5U;
static uint16_t m_metrics1[16U] = {0};
static uint16_t m_metrics2[16U] = {0};
static uint64_t m_decisions[300U] = {0};
//NOTE:
static uint16_t m_metrics1[16U];
static uint16_t m_metrics2[16U];
static uint64_t m_decisions[300U]; //300
static uint16_t * m_oldMetrics = NULL;
static uint16_t * m_newMetrics = NULL;
static uint64_t * m_dp = NULL;
/* Functions ----------------------------------------------------------------*/
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1)
@@ -158,13 +158,15 @@ void CNXDNConvolution_encode(const unsigned char* in, unsigned char* out, unsign
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;
memset(m_metrics1, 0x00U, sizeof(m_metrics1));
memset(m_metrics2, 0x00U, sizeof(m_metrics2));
memset(m_decisions, 0x00U, sizeof(m_decisions));
for (int x = 0; x < 4; x++) CNXDNConvolution_decode(0U, 0U);
}

View File

@@ -25,7 +25,9 @@
#include "dsd.h"
#include "nxdn_const.h"
static const uint8_t scramble_t[] = { //values are the position values we need to invert in the descramble
//NOTE: Descrambling was having an issue without a value inside the brackets, but only when
//the PARITY table was disabled, was this due to a memory issue or overflow?
static const uint8_t scramble_t[182] = { //values are the position values we need to invert in the descramble
2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47,
52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88,
89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134,
@@ -33,16 +35,12 @@ static const uint8_t scramble_t[] = { //values are the position values we need t
168, 170, 171, 174, 175, 176, 177, 181
};
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
};
//decoding functions here
void nxdn_descramble(uint8_t dibits[], int len)
{
for (int i=0; i<sizeof(scramble_t); i++) {
for (int i=0; i<len; i++)
{
if (scramble_t[i] >= len)
break;
dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits
@@ -51,13 +49,15 @@ void nxdn_descramble(uint8_t dibits[], int len)
void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
{
uint8_t deperm[144];
uint8_t depunc[192];
uint8_t trellis_buf[96];
uint8_t deperm[144]; //144
uint8_t depunc[192]; //192
uint8_t trellis_buf[96]; //96
uint16_t crc = 0; //crc calculated by function
uint16_t check = 0; //crc from payload for comparison
int out;
char buf[128];
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<144; i++)
deperm[PERM_16_9[i]] = bits[i];
@@ -70,26 +70,19 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
}
//switch to the convolutional decoder
uint8_t temp[210];
uint8_t temp[200];
uint8_t s0;
uint8_t s1;
uint8_t m_data[13];
uint8_t m_data[20]; //13
memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 192; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+192] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 100U; i++)
for (int i = 0; i < 96; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
@@ -97,7 +90,7 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 96U);
CNXDNConvolution_chainback(m_data, 92);
for(int i = 0; i < 12; i++)
{
@@ -119,28 +112,38 @@ void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144])
}
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
// else if (opts->payload == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
if (opts->payload == 1)
{
fprintf (stderr, "\n");
fprintf (stderr, " FACCH Payload ");
fprintf (stderr, " FACCH1 Payload ");
for (int i = 0; i < 12; i++)
{
fprintf (stderr, "[%02X]", m_data[i]);
}
fprintf (stderr, " - %03X %03X", check, crc);
if (crc != check && opts->payload == 1)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
}
}
//new sacch
//sacch
void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{
uint8_t deperm[60];
uint8_t depunc[72];
uint8_t trellis_buf[32];
uint8_t answer[26];
//see about initializing these variables
uint8_t deperm[60]; //60
uint8_t depunc[72]; //72
uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (trellis_buf, 0, sizeof(trellis_buf));
int o = 0;
uint8_t crc = 0; //value computed by crc6 on payload
uint8_t check = 0; //value pulled from last 6 bits
@@ -166,27 +169,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
}
//switch to the convolutional decoder
uint8_t temp[90];
uint8_t temp[80];
uint8_t s0;
uint8_t s1;
uint8_t m_data[5];
uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+72] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 40U; i++)
for (int i = 0; i < 36; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
@@ -195,7 +191,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
}
//stored as 5 bytes, will need to convert to trellis_buf after running
CNXDNConvolution_chainback(m_data, 36U);
CNXDNConvolution_chainback(m_data, 32);
for(int i = 0; i < 4; i++)
{
@@ -229,7 +225,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
nsf_sacch[i] = trellis_buf[i+8];
}
if (crc == check)
{
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_last_ran = ran;
}
fprintf (stderr, "PF 1/1");
if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, nsf_sacch);
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, nsf_sacch);
//I'm placing this here, my observation is that SACCH NSF
//is almost always, if not always, just IDLE
else fprintf (stderr, " IDLE");
if (opts->payload == 1)
{
@@ -238,8 +247,20 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
{
fprintf (stderr, "[%02X]", m_data[i]);
}
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", check, crc);
if (crc != check)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
}
//reset the sacch field -- Github Issue #118
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));
}
@@ -249,7 +270,7 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
//sf and ran together are denoted as SR in the manual (more confusing acronyms)
//sf (structure field) and RAN will always exist in first 8 bits of each SACCH, then the next 18 bits are the fragment of the superframe
sf = (trellis_buf[0] << 1) | trellis_buf[1];
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
if (sf == 3) part_of_frame = 0;
else if (sf == 2) part_of_frame = 1;
else if (sf == 1) part_of_frame = 2;
@@ -260,12 +281,22 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
fprintf (stderr, "%s", KNRM);
fprintf (stderr, "PF %d/4", part_of_frame+1);
if (crc != check)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
//reset scrambler seed to key value on new superframe
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
if (crc == check)
{
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_ran = state->nxdn_last_ran = ran;
state->nxdn_sf = sf;
state->nxdn_part_of_frame = part_of_frame;
@@ -288,30 +319,33 @@ void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60])
NXDN_SACCH_Full_decode (opts, state);
}
if (opts->payload == 1)
{
fprintf (stderr, "\n");
fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
for (int i = 0; i < 4; i++)
{
fprintf (stderr, "[%02X]", m_data[i]);
}
if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
}
// if (opts->payload == 1)
// {
// fprintf (stderr, "\n");
// fprintf (stderr, " SACCH SF Segment #%d ", part_of_frame+1);
// for (int i = 0; i < 4; i++)
// {
// fprintf (stderr, "[%02X]", m_data[i]);
// }
// // if (crc != check) fprintf (stderr, " CRC ERR - %02X %02X", crc, check);
// }
}
}
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348])
void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348], uint8_t type)
{
uint8_t deperm[348];
uint8_t depunc[406];
uint8_t trellis_buf[199];
uint8_t deperm[348]; //348
uint8_t depunc[406]; //406
uint8_t trellis_buf[208]; //199
int id = 0;
uint16_t crc = 0;
uint16_t check = 0;
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<348; i++) {
deperm[PERM_12_29[i]] = bits[i];
}
@@ -333,26 +367,19 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
}
//switch to the convolutional decoder
uint8_t temp[220];
uint8_t temp[406];
uint8_t s0;
uint8_t s1;
uint8_t m_data[26];
uint8_t m_data[26]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 406; i++)
{
temp[i] = depunc[i] << 1;
}
for (int i = 0; i < 8; i++)
{
temp[i+203] = 0;
}
CNXDNConvolution_start();
for (int i = 0U; i < 207U; i++)
for (int i = 0; i < 203; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
@@ -361,7 +388,7 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
}
//numerals seem okay now
CNXDNConvolution_chainback(m_data, 203U);
CNXDNConvolution_chainback(m_data, 199);
for(int i = 0; i < 26; i++)
{
@@ -382,46 +409,81 @@ void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[34
check = check | trellis_buf[i+184];
}
uint8_t f2u_message_buffer[199];
fprintf (stderr, "%s", KYEL);
if (type == 0) fprintf (stderr, " UDCH");
if (type == 1) fprintf (stderr, " FACCH2");
fprintf (stderr, "%s", KNRM);
uint8_t f2u_message_buffer[400]; //199
memset (f2u_message_buffer, 0, sizeof(f2u_message_buffer));
//just going to leave this all here in case its needed, like in cac,
//don't have any samples with f2 or udch data in it
for (int i = 0; i < 199-8; i++)
for (int i = 0; i < 199-8-15; i++)
{
f2u_message_buffer[i] = trellis_buf[i+8];
}
if (crc == check)
{
fprintf (stderr, " F2/U ");
//NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, f2u_message_buffer);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
// else if (opts->aggressive_framesync == 0)
// {
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, f2u_message_buffer);
// if (type == 0) {} //need handling for user data (text messages and AVL)
// }
if (opts->payload == 1)
{
fprintf (stderr, "\n");
fprintf (stderr, " F2/U Payload\n ");
if (type == 0) fprintf (stderr, " UDCH");
if (type == 1) fprintf (stderr, " FACCH2");
fprintf (stderr, " Payload\n ");
for (int i = 0; i < 26; i++)
{
if (i == 13) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", m_data[i]);
if (i == 12) fprintf (stderr, "\n ");
}
if (crc != check) fprintf (stderr, " CRC ERR ");
if (crc != check)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
// if (crc != check) fprintf (stderr, " CRC ERR ");
if (type == 0)
{
fprintf (stderr, "\n UDCH Data: ASCII - " );
for (int i = 0; i < 24; i++) //remove crc portion
{
if (m_data[i] <= 0x7E && m_data[i] >=0x20)
{
fprintf (stderr, "%c", m_data[i]);
}
else fprintf (stderr, " ");
}
}
}
}
void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
{
uint8_t deperm[300];
uint8_t depunc[350];
uint8_t trellis_buf[171];
uint8_t deperm[300]; //300
uint8_t depunc[350]; //350
uint8_t trellis_buf[176]; //176
int id = 0;
int ran = 0;
uint16_t crc = 0;
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
for (int i=0; i<300; i++) {
deperm[PERM_12_25[i]] = bits[i];
}
@@ -443,21 +505,19 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
}
//switch to the convolutional decoder
uint8_t temp[360];
uint8_t temp[179];
uint8_t s0;
uint8_t s1;
uint8_t m_data[26];
uint8_t m_data[22]; //26
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
for (int i = 0; i < 350; i++)
{
temp[i] = depunc[i] << 1;
}
CNXDNConvolution_start();
for (int i = 0U; i < 179U; i++)
for (int i = 0; i < 175; i++) //179
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
@@ -465,7 +525,7 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 175U);
CNXDNConvolution_chainback(m_data, 171); //175
for(int i = 0; i < 22; i++)
{
@@ -481,21 +541,38 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
crc = crc16cac(trellis_buf, 171);
uint8_t cac_message_buffer[171];
uint8_t cac_message_buffer[147]; //171
memset (cac_message_buffer, 0, sizeof(cac_message_buffer));
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field
for (int i = 0; i < 160; i++)
//shift the cac_message into the appropriate byte arrangement for element_decoder -- skip SR field and ending crc
for (int i = 0; i < 147; i++)
{
cac_message_buffer[i] = trellis_buf[i+8];
}
if (state->nxdn_last_ran != -1) fprintf (stderr, " RAN %02d ", state->nxdn_last_ran);
else fprintf (stderr, " ");
if (crc == 0)
{
fprintf (stderr, " CAC ");
NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7];
state->nxdn_last_ran = ran;
}
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " CAC");
fprintf (stderr, "%s", KNRM);
if (crc != 0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, cac_message_buffer);
// else if (opts->aggressive_framesync == 0) NXDN_Elements_Content_decode(opts, state, 0, cac_message_buffer);
if (opts->payload == 1)
{
fprintf (stderr, "\n");
@@ -505,32 +582,312 @@ void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300])
fprintf (stderr, "[%02X]", m_data[i]);
if (i == 10) fprintf (stderr, "\n ");
}
if (crc != 0) fprintf (stderr, " CRC ERR ");
// if (crc != 0) fprintf (stderr, " CRC ERR ");
}
}
//Type-D "IDAS"
void nxdn_deperm_scch(dsd_opts * opts, dsd_state * state, uint8_t bits[60], uint8_t direction)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " SCCH");
//see about initializing these variables
uint8_t deperm[60]; //60
uint8_t depunc[72]; //72
uint8_t trellis_buf[32]; //32
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (trellis_buf, 0, sizeof(trellis_buf));
int o = 0;
uint8_t crc = 0; //value computed by crc7 on payload
uint8_t check = 0; //value pulled from last 7 bits
int sf = 0;
int part_of_frame = 0;
for (int i=0; i<60; i++)
deperm[PERM_12_5[i]] = bits[i];
for (int p=0; p<60; p+= 10) {
depunc[o++] = deperm[p+0];
depunc[o++] = deperm[p+1];
depunc[o++] = deperm[p+2];
depunc[o++] = deperm[p+3];
depunc[o++] = deperm[p+4];
depunc[o++] = 0;
depunc[o++] = deperm[p+5];
depunc[o++] = deperm[p+6];
depunc[o++] = deperm[p+7];
depunc[o++] = deperm[p+8];
depunc[o++] = deperm[p+9];
depunc[o++] = 0;
}
//switch to the convolutional decoder
uint8_t temp[72];
uint8_t s0;
uint8_t s1;
uint8_t m_data[5]; //5
memset (temp, 0, sizeof (temp));
memset (m_data, 0, sizeof (m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
for (int i = 0; i < 72; i++)
temp[i] = depunc[i] << 1;
CNXDNConvolution_start();
for (int i = 0; i < 36; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 32);
for(int i = 0; i < 4; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
crc = crc7_scch(trellis_buf, 25);
for (int i = 0; i < 7; i++)
{
check = check << 1;
check = check | trellis_buf[i+25];
}
//check the sf early for scrambler reset, if required
sf = (trellis_buf[0] << 1) | trellis_buf[1];
if (sf == 3) part_of_frame = 0;
else if (sf == 2) part_of_frame = 1;
else if (sf == 1) part_of_frame = 2;
else if (sf == 0) part_of_frame = 3;
else part_of_frame = 0;
//reset scrambler seed to key value on new superframe
if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0;
/*
4.3.2. Mapping to Functional Channel
When Subscriber Unit performs voice communication in RTCH2, SCCH is allocated as
described below.
SCCH has super Frame Structure with 4 frame unit during communication, and has non
super Frame Structure with single frame unit at the start time and end time of sending.
Allocation of the other channel is not specified particularly.
*/
//English Translation: Superframe when voice, Non Superframe when not voice
//What I've found is that by not using the superframe structure, and decoding each 'unit'
//individually instead, we can get more expedient decoding on elements without having to
//sacrifice an entire superframe for one bad CRC, also each element cleanly divides into a
//single 'unit' except for enc parms IV, which can be stored seperately if needed
//NOTE: scch has its own message format, and thus, doesn't go to content element decoding
//like everything else does
if (crc == check) NXDN_decode_scch (opts, state, trellis_buf, direction);
// else if (opts->aggressive_framesync == 0) NXDN_decode_scch (opts, state, trellis_buf, direction);
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1)
{
fprintf (stderr, "\n SCCH Payload ");
for (int i = 0; i < 4; i++)
{
fprintf (stderr, "[%02X]", m_data[i]);
}
if (crc != check)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
}
fprintf (stderr, "%s", KNRM);
}
void nxdn_deperm_facch3_udch2(dsd_opts * opts, dsd_state * state, uint8_t bits[288], uint8_t type)
{
uint8_t deperm[144]; //144
uint8_t depunc[192]; //192
uint8_t trellis_buf[96]; //96
uint8_t f3_udch2[288]; //completed bitstream without crc and tailing bits attached
uint8_t f3_udch2_bytes[36]; //completed bytes - with crc and tail
uint16_t crc[2]; //crc calculated by function
uint16_t check[2]; //crc from payload for comparison
int out;
//switch to the convolutional decoder
uint8_t temp[192];
uint8_t s0;
uint8_t s1;
uint8_t m_data[12]; //13
memset (temp, 0, sizeof(temp));
memset (m_data, 0, sizeof(m_data));
memset (trellis_buf, 0, sizeof(trellis_buf));
memset (deperm, 0, sizeof(deperm));
memset (depunc, 0, sizeof(depunc));
memset (crc, 0, sizeof(crc));
memset (check, 0, sizeof(check));
memset (f3_udch2, 0, sizeof(f3_udch2));
memset (f3_udch2_bytes, 0, sizeof(f3_udch2_bytes));
for (int j=0; j<2; j++)
{
for (int i=0; i<144; i++)
deperm[PERM_16_9[i]] = bits[i+(j*144)];
out = 0;
for (int i=0; i<144; i+=3) {
depunc[out++] = deperm[i+0];
depunc[out++] = 0;
depunc[out++] = deperm[i+1];
depunc[out++] = deperm[i+2];
}
for (int i = 0; i < 192; i++)
temp[i] = depunc[i] << 1;
CNXDNConvolution_start();
for (int i = 0; i < 96; i++)
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 92);
for(int i = 0; i < 12; i++)
{
trellis_buf[(i*8)+0] = (m_data[i] >> 7) & 1;
trellis_buf[(i*8)+1] = (m_data[i] >> 6) & 1;
trellis_buf[(i*8)+2] = (m_data[i] >> 5) & 1;
trellis_buf[(i*8)+3] = (m_data[i] >> 4) & 1;
trellis_buf[(i*8)+4] = (m_data[i] >> 3) & 1;
trellis_buf[(i*8)+5] = (m_data[i] >> 2) & 1;
trellis_buf[(i*8)+6] = (m_data[i] >> 1) & 1;
trellis_buf[(i*8)+7] = (m_data[i] >> 0) & 1;
}
crc[j] = crc12f (trellis_buf, 84); //84
for (int i = 0; i < 12; i++)
{
check[j] = check[j] << 1;
check[j] = check[j] | trellis_buf[84+i]; //84
}
//transfer to storage sans crc and tail bits
for (int i = 0; i < 80; i++) f3_udch2[i+(j*80)] = trellis_buf[i];
for (int i = 0; i < 12; i++) f3_udch2_bytes[i+(j*12)] = m_data[i];
}
fprintf (stderr, "%s", KYEL);
if (type == 0) fprintf (stderr, " UDCH2");
if (type == 1) fprintf (stderr, " FACCH3");
fprintf (stderr, "%s", KNRM);
if (crc[0] == check[0] && crc[1] == check[1])
{
if (type == 1) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf);
if (type == 0) ; //need handling for user data (text messages and AVL)
}
// else if (opts->aggressive_framesync == 0)
// {
// if (type == 1) NXDN_Elements_Content_decode(opts, state, 0, trellis_buf);
// if (type == 0) {} //need handling for user data (text messages and AVL)
// }
if (opts->payload == 1)
{
fprintf (stderr, "\n");
if (type == 0) fprintf (stderr, " UDCH2");
if (type == 1) fprintf (stderr, " FACCH3");
fprintf (stderr, " Payload \n ");
for (int i = 0; i < 24; i++)
{
if (i == 12) fprintf (stderr, "\n ");
fprintf (stderr, "[%02X]", f3_udch2_bytes[i]);
}
if ( (crc[0] != check[0] || crc[1] != check[1]) && opts->payload == 1)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
// fprintf (stderr, " - %03X %03X", check[0], crc[0]);
// fprintf (stderr, " - %03X %03X", check[1], crc[1]);
}
if (type == 0)
{
fprintf (stderr, "\n UDCH2 Data: ASCII - " );
for (int i = 0; i < 22; i++) //all but last crc portion
{
if (i == 12) i = 14; //skip first crc portion
if (f3_udch2_bytes[i] <= 0x7E && f3_udch2_bytes[i] >=0x20)
{
fprintf (stderr, "%c", f3_udch2_bytes[i]);
}
else fprintf (stderr, " ");
}
}
}
}
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
{
//NOTE: Most Req/Resp (request and respone) share same message type but differ depending on channel type
//RTCH Outbound will take precedent when differences may occur (except CALL_ASSGN)
fprintf (stderr, "%s", KYEL);
if (MessageType == 0x10) fprintf(stderr, " IDLE");
else if (MessageType == 0x11) fprintf(stderr, " DISC"); //disconnect
else if (MessageType == 0x00) fprintf(stderr, " CALL_RESP");
else if (MessageType == 0x01) fprintf(stderr, " VCALL");
else if (MessageType == 0x03) fprintf(stderr, " VCALL IV");
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
else if (MessageType == 0x02) fprintf(stderr, " VCALL_REC_REQ");
else if (MessageType == 0x03) fprintf(stderr, " VCALL_IV");
else if (MessageType == 0x04) fprintf(stderr, " VCALL_ASSGN");
else if (MessageType == 0x05) fprintf(stderr, " VCALL_ASSGN_DUP");
else if (MessageType == 0x06) fprintf(stderr, " CALL_CONN_RESP");
else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX");
else if (MessageType == 0x08) fprintf(stderr, " TX_REL");
else if (MessageType == 0x09) fprintf(stderr, " DCALL_HEADER");
else if (MessageType == 0x0A) fprintf(stderr, " DCALL_REC_REQ");
else if (MessageType == 0x0B) fprintf(stderr, " DCALL_UDATA");
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
else if (MessageType == 0x0D) fprintf(stderr, " DCALL_ASSGN_DUP");
else if (MessageType == 0x0E) fprintf(stderr, " DCALL_ASSGN");
else if (MessageType == 0x11) fprintf(stderr, " DISC");
else if (MessageType == 0x17) fprintf(stderr, " DST_ID_INFO");
else if (MessageType == 0x18) fprintf(stderr, " SITE_INFO");
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO");
else if (MessageType == 0x1A) fprintf(stderr, " CCH_INFO");
else if (MessageType == 0x1B) fprintf(stderr, " ADJ_SITE_INFO");
else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO");
else if (MessageType == 0x20) fprintf(stderr, " REG_RESP");
else if (MessageType == 0x22) fprintf(stderr, " REG_C_RESP");
else if (MessageType == 0x24) fprintf(stderr, " GRP_REG_RESP");
@@ -539,24 +896,23 @@ void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType)
else if (MessageType == 0x38) fprintf(stderr, " SDCALL_REQ_HEADER");
else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA");
else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP");
else if (MessageType == 0x3F) fprintf(stderr, " ALIAS");
else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK");
else fprintf(stderr, " Unknown M-%02X", MessageType);
fprintf (stderr, "%s", KNRM);
//zero out stale values so they won't persist after a transmit release
//disable if random messages wipe out the alias
if (MessageType == 0x08 || MessageType == 0x10) //idle, tx_rel
//Zero out stale values on DISC or TX_REL only (IDLE messaages occur often on NXDN96 VCH, and randomly on Type-C FACCH1 steals for some reason)
if (MessageType == 0x08 || MessageType == 0x11)
{
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
state->nxdn_last_rid = 0;
state->nxdn_last_tg = 0;
state->nxdn_cipher_type = 0;
state->nxdn_cipher_type = 0; //force will reactivate it if needed during voice tx
if (state->keyloader == 1) state->R = 0;
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
memset (state->nxdn_sacch_frame_segment, 1, sizeof(state->nxdn_sacch_frame_segment));
sprintf (state->nxdn_call_type, "%s", "");
}
}
}
//voice descrambler
@@ -668,4 +1024,23 @@ static uint16_t crc16cac(const uint8_t buf[], int len)
}
crc = crc ^ 0xffff;
return crc & 0xffff;
}
static uint8_t crc7_scch(uint8_t bits[], int len)
{
uint8_t s[7];
uint8_t a;
for (int i=0;i<7;i++)
s[i] = 1;
for (int i=0;i<len;i++) {
a = bits[i] ^ s[0];
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = a ^ s[4];
s[4] = s[5];
s[5] = s[6];
s[6] = a;
}
return load_i(s, 7);
}

File diff suppressed because it is too large Load Diff

View File

@@ -32,53 +32,74 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
// length is implicitly 192, with frame sync in first 10 dibits
uint8_t dbuf[182];
uint8_t lich;
int answer_len=0;
int answer_len = 0;
uint8_t answer[32];
uint8_t sacch_answer[32];
int lich_parity_received;
int lich_parity_computed;
int voice=0;
int facch=0;
int facch2=0;
int sacch=0;
int cac=0;
int voice = 0;
int facch = 0;
int facch2 = 0;
int udch = 0;
int sacch = 0;
int cac = 0;
int sr_structure;
int sr_ran;
uint8_t lich_dibits[8] = {0};
uint8_t sacch_bits[60] = {0};
uint8_t facch_bits_a[144] = {0};
uint8_t facch_bits_b[144] = {0};
uint8_t cac_bits[300] = {0};
uint8_t facch2_bits[348] = {0}; //facch2 or udch, same amount of bits
//new, and even more confusing NXDN Type-D / "IDAS" acronyms
int idas = 0;
int scch = 0;
int facch3 = 0;
int udch2 = 0;
//nxdn bit buffer, for easy assignment handling
int nxdn_bit_buffer[364] = {0};
int nxdn_dibit_buffer[182] = {0};
//new breakdown of lich codes
uint8_t lich_rf = 0; //RF Channel Type
uint8_t lich_fc = 0; //Functional Channel Type
uint8_t lich_op = 0; //Options
uint8_t direction; //inbound or outbound direction
uint8_t lich_dibits[8];
uint8_t sacch_bits[60];
uint8_t facch_bits_a[144];
uint8_t facch_bits_b[144];
uint8_t cac_bits[300];
uint8_t facch2_bits[348]; //facch2 or udch, same amount of bits
uint8_t facch3_bits[288]; //facch3 or udch2, same amount of bits
//nxdn bit buffer, for easy assignment handling
int nxdn_bit_buffer[364];
int nxdn_dibit_buffer[182];
//init all arrays
memset (dbuf, 0, sizeof(dbuf));
memset (answer, 0, sizeof(answer));
memset (sacch_answer, 0, sizeof(sacch_answer));
memset (lich_dibits, 0, sizeof(lich_dibits));
memset (sacch_bits, 0, sizeof(sacch_bits));
memset (facch_bits_b, 0, sizeof(facch_bits_b));
memset (facch_bits_a, 0, sizeof(facch_bits_a));
memset (cac_bits, 0, sizeof(cac_bits));
memset (facch2_bits, 0, sizeof(facch2_bits));
memset (nxdn_bit_buffer, 0, sizeof(nxdn_bit_buffer));
memset (nxdn_dibit_buffer, 0, sizeof(nxdn_dibit_buffer));
//collect lich bits first, if they are good, then we can collect the rest of them
for (int i = 0; i < 8; i++)
{
lich_dibits[i] = dbuf[i] = getDibit(opts, state);
}
for (int i = 0; i < 8; i++) lich_dibits[i] = dbuf[i] = getDibit(opts, state);
nxdn_descramble (lich_dibits, 8);
lich = 0;
for (int i=0; i<8; i++)
{
lich |= (lich_dibits[i] >> 1) << (7-i);
}
for (int i=0; i<8; i++) lich |= (lich_dibits[i] >> 1) << (7-i);
lich_parity_received = lich & 1;
lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1;
lich = lich >> 1;
if (lich_parity_received != lich_parity_computed)
{
//fprintf(stderr, "NXDN lich parity error, ignoring frame \n");
return;
{
if (opts->payload == 1) fprintf(stderr, " Lich Parity Error %02X\n", lich);
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
goto END;
}
voice = 0;
@@ -92,6 +113,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (lich % 2 == 0 && opts->p25_trunk == 1)
{
if (opts->payload == 1) fprintf(stderr, " Simplex/Inbound NXDN lich on trunking system - type 0x%02X\n", lich);
state->lastsynctype = -1; //set to -1 so we don't jump back here too quickly
goto END;
}
@@ -102,21 +124,20 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
break;
case 0x28: //facch2 types
case 0x29:
case 0x2e:
case 0x2f:
case 0x48:
case 0x49:
facch2 = 1;
break;
case 0x2e: //udch types
case 0x2f:
case 0x4e:
case 0x4f:
case 0x69:
case 0x6f:
facch2 = 1;
udch = 1;
break;
case 0x32: //facch in 1, vch in 2
case 0x33:
case 0x52:
case 0x53:
case 0x73:
voice = 2;
facch = 1;
sacch = 1;
@@ -124,8 +145,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x34: //vch in 1, facch in 2
case 0x35:
case 0x54:
case 0x55:
case 0x75:
case 0x55: //disabled for testing, IDAS system randomly triggers this one, probably due to poor signal
voice = 1;
facch = 2;
sacch = 1;
@@ -134,7 +154,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x37:
case 0x56:
case 0x57:
case 0x77:
voice = 3;
facch = 0;
sacch = 1;
@@ -147,8 +166,6 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x41:
case 0x50:
case 0x51:
case 0x61:
case 0x71:
voice = 0;
facch = 3;
sacch = 1;
@@ -157,6 +174,59 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
case 0x39:
sacch = 1;
break;
//NXDN "Type-D" or "IDAS" Specific Lich Codes
case 0x76: //normal vch voice (in one and two)
case 0x77:
idas = 1;
scch = 1;
voice = 3;
break;
case 0x74: //vch in 1, facch1 in 2 (facch 2 steal)
case 0x75:
idas = 1;
scch = 1;
voice = 1;
facch = 2;
break;
case 0x72: //facch in 1, vch in 2 (facch 1 steal)
case 0x73:
idas = 1;
scch = 1;
voice = 2;
facch = 1;
break;
case 0x70: //facch steal in vch 1 and vch 2 (during voice only)
case 0x71:
idas = 1;
scch = 1;
facch = 3;
break;
case 0x6E: //udch2
case 0x6F:
idas = 1;
scch = 1;
udch2 = 1;
break;
case 0x68:
case 0x69: //facch3
idas = 1;
scch = 1;
facch3 = 1;
break;
case 0x62:
case 0x63: //facch1 in 1, null data and post field in 2
idas = 1;
scch = 1;
facch = 1;
break;
case 0x60:
case 0x61: //facch1 in both (non vch)
idas = 1;
scch = 1;
facch = 3;
break;
default:
if (opts->payload == 1) fprintf(stderr, " false sync or unsupported NXDN lich type 0x%02X\n", lich);
//reset the sacch field, we probably got a false sync and need to wipe or give a bad crc
@@ -168,17 +238,29 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
break;
} // end of switch(lich)
//enable these after good lich parity and known lich value
state->carrier = 1;
state->last_cc_sync_time = time(NULL);
//printframesync after determining we have a good lich and it has something in it
if (voice || facch || sacch || facch2 || cac)
if (idas)
{
if (opts->frame_nxdn48 == 1)
{
printFrameSync (opts, state, "IDAS D ", 0, "-");
}
if (opts->payload == 1)
fprintf (stderr, "L%02X - ", lich);
}
else if (voice || facch || sacch || facch2 || udch || cac)
{
// if (state->synctype == 28) fprintf (stderr, " +");
// else fprintf (stderr, " -");
if (opts->frame_nxdn48 == 1)
{
printFrameSync (opts, state, "NXDN48 ", 0, "-");
}
else printFrameSync (opts, state, "NXDN96 ", 0, "-");
if (opts->payload == 1) fprintf (stderr, "L%02X -", lich);
if (opts->payload == 1)
fprintf (stderr, "L%02X - ", lich);
}
//now that we have a good LICH, we can collect all of our dibits
@@ -197,7 +279,7 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
nxdn_bit_buffer[i*2+1] = dbuf[i] & 1;
}
//sacch
//sacch or scch bits
for (int i = 0; i < 60; i++)
{
sacch_bits[i] = nxdn_bit_buffer[i+16];
@@ -222,23 +304,122 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
facch2_bits[i] = nxdn_bit_buffer[i+16];
}
//udch2 or facch3
for (int i = 0; i < 288; i++)
{
facch3_bits[i] = nxdn_bit_buffer[i+16+60];
}
//vch frames stay inside dbuf, easier to assign that to ambe_fr frames
//sacch needs extra handling depending on superframe or non-superframe variety
if (voice)
//Add advanced decoding of LICH (RF, FC, OPT, and Direction
lich_rf = (lich >> 5) & 0x3;
lich_fc = (lich >> 3) & 0x3;
lich_op = (lich >> 1) & 0x3;
if (lich % 2 == 0) direction = 0;
else direction = 1;
// RF Channel Type
if (lich_rf == 0) fprintf (stderr, "RCCH ");
else if (lich_rf == 1) fprintf (stderr, "RTCH ");
else if (lich_rf == 2) fprintf (stderr, "RDCH ");
else
{
if (lich < 0x60) fprintf (stderr, "RTCH_C ");
else fprintf (stderr, "RTCH2 ");
}
// Functional Channel Type -- things start to get really convoluted here
// These will echo when handled, either with the decoded message type, or relevant crc err
// if (lich_rf == 0) //CAC Type
// {
// //Technically, we should be checking direction as well, but the fc never has split meaning on CAC
// if (lich_fc == 0) fprintf (stderr, "CAC ");
// else if (lich_fc == 1) fprintf (stderr, "Long CAC ");
// else if (lich_fc == 3) fprintf (stderr, "Short CAC ");
// else fprintf (stderr, "Reserved ");
// }
// else //USC Type
// {
// if (lich_fc == 0) fprintf (stderr, "NSF SACCH ");
// else if (lich_fc == 1) fprintf (stderr, "UDCH ");
// else if (lich_fc == 2) fprintf (stderr, "SF SACCH ");
// else if (lich_fc == 3) fprintf (stderr, "SF SACCH/IDLE ");
// }
#ifdef LIMAZULUTWEAKS
//LimaZulu specific tweak, load keys from frequency value, if avalable -- test before VCALL
//needs to be loaded here, if superframe data pair, then we need to run the LFSR on it as well
if (voice) //can this run TOO frequently?
{
long int freq = 0;
uint8_t hash_bits[24];
memset (hash_bits, 0, sizeof(hash_bits));
uint16_t limazulu = 0;
//if not available, then poll rigctl if its available
if (opts->use_rigctl == 1)
freq = GetCurrentFreq (opts->rigctl_sockfd);
//if using rtl input, we can ask for the current frequency tuned
else if (opts->audio_in_type == 3)
freq = (long int)opts->rtlsdr_center_freq;
// freq = 167831250; //hardset for testing
//since a frequency value will be larger than the 16-bit max, we need to hash it first
//the hash has to be run the same way as the import, so at a 24-bit depth, which hopefully
//will not lead to any duplicate key loads due to multiple CRC16 collisions on a larger value?
for (int i = 0; i < 24; i++)
hash_bits[i] = ((freq << i) & 0x800000) >> 23; //load into array for CRC16
if (freq) limazulu = ComputeCrcCCITT16d (hash_bits, 24);
limazulu = limazulu & 0xFFFF; //make sure no larger than 16-bits
fprintf (stderr, "%s", KYEL);
if (freq) fprintf (stderr, "\n Freq: %ld - Freq Hash: %d", freq, limazulu);
if (state->rkey_array[limazulu] != 0) fprintf (stderr, " - Key Loaded: %lld", state->rkey_array[limazulu]);
fprintf (stderr, "%s", KNRM);
if (state->rkey_array[limazulu] != 0)
state->R = state->rkey_array[limazulu];
if (state->R != 0 && state->M == 1) state->nxdn_cipher_type = 0x1;
//add additional time to last_sync_time for LimaZulu to hold on current frequency
//a little longer without affecting normal scan time on trunk_hangtime variable
state->last_cc_sync_time = time(NULL) + 2; //ask him for an ideal wait timer
}
#endif //end LIMAZULUTWEAKS
if (opts->scanner_mode == 1)
state->last_cc_sync_time = time(NULL) + 2; //add a little extra hangtime between resuming scan
//Option/Steal Flags echoed in Voice, V+F, or Data
if (voice && !facch) //voice only, no facch steal
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Voice ");
fprintf (stderr, "%s", KNRM);
}
else
else if (voice && facch) //voice with facch1 steal
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " V%d+F%d ", 3 - facch, facch); //print which position on each
fprintf (stderr, "%s", KNRM);
}
else //Covers FACCH1 in both, FACCH2, UDCH, UDCH2, CAC
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, " Data ");
fprintf (stderr, "%s", KNRM);
//roll the voice scrambler LFSR here if key available to advance seed (usually just needed on NXDN96)
if (state->nxdn_cipher_type == 0x1 && state->R != 0) //!voice, or voice == 0
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
{
char ambe_temp[49] = {0};
char ambe_d[49] = {0};
@@ -248,41 +429,98 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
}
}
}
}
if (voice && facch == 1) //facch steal 1 -- before voice
{
//force scrambler here, but with unspecified key (just use what's loaded)
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
{
char ambe_temp[49] = {0};
char ambe_d[49] = {0};
for (int i = 0; i < 2; i++)
{
LFSRN(ambe_temp, ambe_d, state);
}
}
}
if (lich == 0x20 || lich == 0x21 || lich == 0x61 || lich == 0x40 || lich == 0x41) state->nxdn_sacch_non_superframe = TRUE;
else state->nxdn_sacch_non_superframe = FALSE;
if (sacch)nxdn_deperm_sacch(opts, state, sacch_bits);
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits);
//TODO Later: Add Direction and/or LICH to all decoding functions
if (scch) nxdn_deperm_scch (opts, state, sacch_bits, direction);
if (udch2) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 0);
if (facch3) nxdn_deperm_facch3_udch2(opts, state, facch3_bits, 1);
if (sacch) nxdn_deperm_sacch(opts, state, sacch_bits);
if (cac) nxdn_deperm_cac(opts, state, cac_bits);
//Seperated UDCH user data from facch2 data
if (udch) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 0);
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits, 1);
//SHOULD be okay to run facch1's again on steal frames, will need testing
// if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
// if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
//only run facch in second slot if its not equal to the first one
//ideally, this would work better AFTER decoding/FEC
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
if (facch & 2)
{
if (memcmp (facch_bits_a, facch_bits_b, 144) != 0)
nxdn_deperm_facch(opts, state, facch_bits_b);
}
if (voice)
{
//restore MBE file open here
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
//update last voice sync time
state->last_vc_sync_time = time(NULL);
//turn on scrambler if forced by user option
if (state->M == 1 && state->R != 0) state->nxdn_cipher_type = 0x1;
//process voice frame
nxdn_voice (opts, state, voice, dbuf);
}
//close MBE file if no voice and its open
if (!voice)
{
if (opts->mbe_out_f != NULL)
{
if (opts->frame_nxdn96 == 1) //nxdn96 has voice and data mixed together, so we will need to do a time check first
if (opts->frame_nxdn96 == 1) //nxdn96 has pure voice and data frames mixed together, so we will need to do a time check first
{
if ( (time(NULL) - state->last_vc_sync_time) > 1) //test for optimal time, 1 sec should be okay
{
closeMbeOutFile (opts, state);
}
}
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice mixing
//may need to reconsider this, due to double FACCH1 steals on some Type-C (ASSGN_DUP, etc) and Conventional Systems (random IDLE FACCH1 steal for no reason)
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice frames mixing
}
}
}
if (voice && facch == 2) //facch steal 2 -- after voice 1
{
//roll the voice scrambler LFSR here if key available to advance seed -- half rotation on a facch steal
if (state->nxdn_cipher_type == 0x1 && state->R != 0)
{
char ambe_temp[49] = {0};
char ambe_d[49] = {0};
for (int i = 0; i < 2; i++)
{
LFSRN(ambe_temp, ambe_d, state);
}
}
}
if (opts->payload == 1 && !voice) fprintf (stderr, "\n");
else if (opts->payload == 0) fprintf (stderr, "\n");
fprintf (stderr, "\n");
END: ; //do nothing
}

View File

@@ -2,7 +2,7 @@
* p25_frequency.c
* P25 Channel to Frequency Calculator
*
* NXDN Channel to Frequency, Courtesy of IcomIcR20 and EricCottrell (base values)
* NXDN Channel to Frequency Calculator
*
* LWVMOBILE
* 2022-11 DSD-FME Florida Man Edition
@@ -59,16 +59,16 @@ long int process_channel_to_freq (dsd_opts * opts, dsd_state * state, int channe
}
//NXDN Channel to Frequency, Courtesy of IcomIcR20 on RR Forums
long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t channel)
{
long int freq;
long int base = 0;
long int step = 0;
//the base freq value is per EricCottrell in the Understanding NXDN Trunking Forum Thread
//will need to do some research or tests to confirm these values are accurate
//reworked to include Direct Frequency Assignment if available
//first, check channel map
//first, check channel map for imported value, DFA systems most likely won't need an import,
//unless it has 'system definable' attributes
if (state->trunk_chan_map[channel] != 0)
{
freq = state->trunk_chan_map[channel];
@@ -76,33 +76,41 @@ long int nxdn_channel_to_frequency(dsd_opts * opts, dsd_state * state, uint16_t
return (freq);
}
//if not found, attempt to find it via calculation
else
//then, let's see if its DFA instead -- 6.5.36
else if (state->nxdn_rcn == 1)
{
if ((channel > 0) && (channel <= 400))
{
if (opts->frame_nxdn48 == 1) base = 450000000;
else base = 451000000;
//determine the base frequency in Hz
if (state->nxdn_base_freq == 1) base = 100000000; //100 MHz
else if (state->nxdn_base_freq == 2) base = 330000000; //330 Mhz
else if (state->nxdn_base_freq == 3) base = 400000000; //400 Mhz
else if (state->nxdn_base_freq == 4) base = 750000000; //750 Mhz
else base = 0; //just set to zero, will be system definable most likely and won't be able to calc
freq = base + (channel - 1) * 12500;
fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
//determine the step value in Hz
if (state->nxdn_step = 2) step = 1250; //1.25 kHz
else if (state->nxdn_step = 3) step = 3125; //3.125 kHz
else step = 0; //just set to zero, will be system definable most likely and won't be able to calc
//if we have a valid base and step, then calc frequency
//6.5.45. Outbound/Inbound Frequency Number (OFN/IFN)
if (base && step)
{
freq = base + (channel * step);
fprintf (stderr, "\n DFA Frequency [%.6lf] MHz", (double)freq/1000000);
return (freq);
}
else if ((channel >= 401) && (channel <= 800))
else
{
if (opts->frame_nxdn48 == 1) base = 460000000;
else base = 461000000;
freq = base + (channel - 401) * 12500;
fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
return (freq);
}
else
{
fprintf(stderr, "\n Non-standard frequency or channel not found in import file");
fprintf(stderr, "\n Custom DFA Settings -- Unknown Freq;");
return (0);
}
}
else
{
fprintf(stderr, "\n Channel not found in import file");
return (0);
}
}

View File

@@ -1,160 +1,363 @@
/*-------------------------------------------------------------------------------
* p25_lcw.c
* P25p1 Link Control Word Decoding
*
* LWVMOBILE
* 2023-05 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
void
processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo)
//new p25_lcw function here -- TIA-102.AABF-D LCW Format Messages (if anybody wants to fill the rest out)
void p25_lcw (dsd_opts * opts, dsd_state * state, uint8_t LCW_bits[], uint8_t irrecoverable_errors)
{
uint8_t lc_format = (uint8_t)ConvertBitIntoBytes(&LCW_bits[0], 8); //format
uint8_t lc_opcode = (uint8_t)ConvertBitIntoBytes(&LCW_bits[2], 8); //opcode portion of format
uint8_t lc_mfid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8); //mfid
uint8_t lc_svcopt = (uint8_t)ConvertBitIntoBytes(&LCW_bits[16], 8); //service options
uint8_t lc_pf = LCW_bits[0]; //protect flag
uint8_t lc_sf = LCW_bits[1]; //Implicit / Explicit MFID Format
char tgid[17], tmpstr[255];
long talkgroup, source;
int i, j;
if (lc_pf == 1) //check the protect flag -- if set, its an encrypted lcw
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " LCW Protected ");
fprintf (stderr, "%s",KNRM);
}
tgid[16] = 0;
if (lc_pf == 0) //not protected/encrypted lcw
{
if (opts->p25lc == 1)
{
fprintf (stderr, "lcformat: %s mfid: %s lcinfo: %s ", lcformat, mfid, lcinfo);
if (opts->p25tg == 0)
{
fprintf (stderr, "\n");
}
}
if (opts->payload == 1) fprintf (stderr, " LCW");
if (strcmp (lcformat, "00000100") == 0)
//check to see if we need to run these as MFID 0 or 1 only (standard)
if (lc_mfid == 0 || lc_mfid == 1) //lc_mfid == 0
{
// first tg is the active channel
j = 0;
for (i = 40; i < 52; i++)
//check the service options on applicable formats
if (lc_format == 0x4A || lc_format == 0x46 || lc_format == 0x45
|| lc_format == 0x44 || lc_format == 0x03 || lc_format == 0x00)
{
if (lc_svcopt & 0x80) fprintf (stderr, " Emergency");
if (lc_svcopt & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
if (lc_svcopt & 0x20) fprintf (stderr, " Duplex");
if (lc_svcopt & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (lc_svcopt & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", lc_svcopt & 0x7); //call priority
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
}
if (lc_format == 0x00)
{
fprintf (stderr, " Group Voice Channel User");
uint8_t res = (uint8_t)ConvertBitIntoBytes(&LCW_bits[24], 7);
uint8_t explicit = LCW_bits[24]; //explicit source id required == 1, full SUID on seperate LCW
uint16_t group = (uint16_t)ConvertBitIntoBytes(&LCW_bits[32], 16);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
fprintf (stderr, " - Group %d Source %d", group, source);
//don't set this when zero, annoying blink occurs in ncurses
if (group != 0) state->lasttg = group;
if (source != 0) state->lastsrc = source;
sprintf (state->call_string[0], " Group ");
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
else strcat (state->call_string[0], " ");
}
else if (lc_format == 0x03)
{
fprintf (stderr, " Unit to Unit Voice Channel User");
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[24], 24);
uint32_t source = (uint32_t)ConvertBitIntoBytes(&LCW_bits[48], 24);
fprintf (stderr, " - Target %d Source %d", target, source);
//don't set this when zero, annoying blink occurs in ncurses
if (target != 0) state->lasttg = target;
if (source != 0) state->lastsrc = source;
sprintf (state->call_string[0], " Private ");
if (lc_svcopt & 0x80) strcat (state->call_string[0], " Emergency ");
else if (lc_svcopt & 0x40) strcat (state->call_string[0], " Encrypted ");
else strcat (state->call_string[0], " ");
}
//uses explicit bit?
else if (lc_format == 0x42) //is this group only, or group and private?
{
fprintf (stderr, " Group Voice Channel Update - ");
uint16_t channel1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[8], 16);
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
uint16_t channel2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
uint16_t group2 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
if (channel1 && group1)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
fprintf (stderr, "tg: %li ", talkgroup);
fprintf (stderr, "Ch: %04X TG: %d; ", channel1, group1);
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel1, group1);
state->last_active_time = time(NULL);
}
if (opts->p25tg == 1)
if (channel2 && group2 && group1 != group2)
{
fprintf (stderr, "tg: %li ", talkgroup);
// the remaining 3 appear to be other active tg's on the system
j = 0;
for (i = 28; i < 40; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
fprintf (stderr, "%li ", talkgroup);
j = 0;
for (i = 16; i < 28; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
fprintf (stderr, "%li ", talkgroup);
j = 0;
for (i = 4; i < 16; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
fprintf (stderr, "%li\n", talkgroup);
fprintf (stderr, "Ch: %04X TG: %d; ", channel2, group2);
sprintf (state->active_channel[1], "Active Ch: %04X TG: %d; ", channel2, group2);
state->last_active_time = time(NULL);
}
}
else if (lc_format == 0x44)
{
fprintf (stderr, " Group Voice Channel Update – Explicit");
uint16_t group1 = (uint16_t)ConvertBitIntoBytes(&LCW_bits[24], 16);
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[40], 16);
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[56], 16);
fprintf (stderr, "Ch: %04X TG: %d; ", channelt, group1);
}
else if (lc_format == 0x45)
{
fprintf (stderr, " Unit to Unit Answer Request");
}
else if (lc_format == 0x46)
{
fprintf (stderr, " Telephone Interconnect Voice Channel User");
}
else if (lc_format == 0x47)
{
fprintf (stderr, " Telephone Interconnect Answer Request");
}
else if (lc_format == 0x49)
{
fprintf (stderr, " Souce ID Extension");
}
else if (lc_format == 0x4A)
{
fprintf (stderr, " Unit to Unit Voice Channel User – Extended");
uint32_t target = (uint32_t)ConvertBitIntoBytes(&LCW_bits[16], 24);
uint32_t suid = (uint32_t)ConvertBitIntoBytes(&LCW_bits[40], 24);
fprintf (stderr, "TGT: %04X SUID: %d; ", target, suid);
}
else if (lc_format == 0x50)
{
fprintf (stderr, " Group Affiliation Query");
}
else if (lc_format == 0x51)
{
fprintf (stderr, " Unit Registration Command");
}
else if (lc_format == 0x52) //wonder if anybody uses this if its deleted/obsolete
{
fprintf (stderr, " Unit Authentication Command - OBSOLETE");
}
else if (lc_format == 0x53)
{
fprintf (stderr, " Status Query");
}
else if (lc_format == 0x54)
{
fprintf (stderr, " Status Update");
}
else if (lc_format == 0x55)
{
fprintf (stderr, " Status Update");
}
else if (lc_format == 0x56)
{
fprintf (stderr, " Call Alert");
}
else if (lc_format == 0x57)
{
fprintf (stderr, " Extended Function Command");
}
else if (lc_format == 0x58)
{
fprintf (stderr, " Channel Identifier Update");
}
else if (lc_format == 0x59)
{
fprintf (stderr, " Channel Identifier Update VU");
}
else if (lc_format == 0x5A)
{
fprintf (stderr, " Status Update – Source ID Extension Required");
}
else if (lc_format == 0x5C)
{
fprintf (stderr, " Extended Function Command – Source ID Extension Required");
}
else if (lc_format == 0x60)
{
fprintf (stderr, " System Service Broadcast");
}
else if (lc_format == 0x61)
{
fprintf (stderr, " Secondary Control Channel Broadcast");
}
else if (lc_format == 0x62)
{
fprintf (stderr, " Adjacent Site Status Broadcast");
}
else if (lc_format == 0x63)
{
fprintf (stderr, " RFSS Status Broadcast");
}
else if (lc_format == 0x64)
{
fprintf (stderr, " Network Status Broadcast");
}
else if (lc_format == 0x65)
{
fprintf (stderr, " Protection Parameter Broadcast - OBSOLETE");
}
else if (lc_format == 0x66)
{
fprintf (stderr, " Secondary Control Channel Broadcast – Explicit (LCSCBX)");
}
else if (lc_format == 0x67) //explicit
{
fprintf (stderr, " Adjacent Site Status (LCASBX)");
uint8_t lra = (uint8_t)ConvertBitIntoBytes(&LCW_bits[8], 8);
uint16_t channelt = (uint16_t)ConvertBitIntoBytes(&LCW_bits[16], 16);
uint8_t rfssid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[32], 8);
uint8_t siteid = (uint8_t)ConvertBitIntoBytes(&LCW_bits[40], 8);
uint16_t channelr = (uint16_t)ConvertBitIntoBytes(&LCW_bits[48], 16);
uint8_t cfva = (uint8_t)ConvertBitIntoBytes(&LCW_bits[64], 4);
fprintf (stderr, " - RFSS %d Site %d CH %04X", rfssid, siteid, channelt);
//debug print only
// fprintf (stderr, "\n ");
// fprintf (stderr, " LRA [%02X] RFSS [%03d] SITE [%03d] CHAN-T [%04X] CHAN-R [%02X] CFVA [%X]\n ", lra, rfssid, siteid, channelt, channelr, cfva);
// if (cfva & 0x8) fprintf (stderr, " Conventional");
// if (cfva & 0x4) fprintf (stderr, " Failure Condition");
// if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
// else fprintf (stderr, " Last Known");
if (cfva & 0x1) fprintf (stderr, "- Connection Active");
// process_channel_to_freq (opts, state, channelt);
//end debug, way too much for a simple link control line
}
else if (lc_format == 0x68)
{
fprintf (stderr, " RFSS Status Broadcast – Explicit (LCRSBX)");
}
else if (lc_format == 0x69)
{
fprintf (stderr, " Network Status Broadcast – Explicit (LCNSBX)");
}
else if (lc_format == 0x6A)
{
fprintf (stderr, " Conventional Fallback");
}
else if (lc_format == 0x6B)
{
fprintf (stderr, " Message Update – Source ID Extension Required");
}
//tune back to CC here - save about 1-2 seconds
else if (lc_format == 0x4F) //# Call Termination/Cancellation
{
fprintf (stderr, " Call Termination");
if (opts->p25_trunk == 1 && state->p25_cc_freq != 0 && opts->p25_is_tuned == 1)
{
//Will we need to check for a symbolrate change here, can a P25p2 TDMA-CC system
//revert back to a phase 1 traffic channel or carry a phase 1 traffic channel?
//clear heuristics from current traffic channel
if (opts->frame_p25p1 == 1 && opts->use_heuristics == 1)
{
initialize_p25_heuristics(&state->p25_heuristics);
initialize_p25_heuristics(&state->inv_p25_heuristics);
}
//rigctl
if (opts->use_rigctl == 1)
{
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
// state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->p25_cc_freq);
}
//rtl
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
state->lasttg = 0;
state->lastsrc = 0;
state->payload_algid = 0;
state->payload_keyid = 0;
// state->payload_miP = 0;
//reset some strings
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
sprintf (state->active_channel[0], "%s", "");
sprintf (state->active_channel[1], "%s", "");
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
rtl_dev_tune (opts, state->p25_cc_freq);
#endif
}
}
}
else fprintf (stderr, " Unknown Format %02X MFID %02X SVC %02X", lc_format, lc_mfid, lc_svcopt);
}
else if (strcmp (lcformat, "00000000") == 0)
{
j = 0;
if (strcmp (mfid, "10010000") == 0)
{
for (i = 20; i < 32; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[12] = 48;
tmpstr[13] = 48;
tmpstr[14] = 48;
tmpstr[15] = 48;
}
else
{
for (i = 16; i < 32; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = lcinfo[i];
}
tmpstr[j] = lcinfo[i];
j++;
}
}
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
fprintf (stderr, "tg: %li ", talkgroup);
}
//not a duplicate, this one will print if not MFID 0 or 1
else fprintf (stderr, " Unknown Format %02X MFID %02X ", lc_format, lc_mfid);
}
//ending line break
fprintf (stderr, "\n");
j = 0;
for (i = 32; i < 56; i++)
{
tmpstr[j] = lcinfo[i];
j++;
}
tmpstr[24] = 0;
source = strtol (tmpstr, NULL, 2);
state->lastsrc = source;
if (opts->p25tg == 1)
{
fprintf (stderr, "src: %li emr: %c\n", source, lcinfo[0]);
}
}
else if ((opts->p25tg == 1) && (opts->p25lc == 1))
{
fprintf (stderr, "\n");
}
}

View File

@@ -453,93 +453,53 @@ processHDU(dsd_opts* opts, dsd_state* state)
status = getDibit (opts, state);
//TODO: Do something useful with the status bits...
//if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors??
if (state->carrier == 1)
{
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
state->payload_algid = algidhex;
state->payload_keyid = kidhex;
//state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7);
//state->payload_mfid = strtol (mfid, NULL, 2);
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
state->payload_miP = (mihex1 << 32) | (mihex2);
}
//reset dropbytes - skip first 11 for LCW
state->dropL = 267;
//set vc counter to 0
state->p25vc = 0;
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
if (irrecoverable_errors == 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX MFID: 0x%02X", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid);
fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
state->payload_algid = algidhex;
state->payload_keyid = kidhex;
if (state->R != 0 && state->payload_algid == 0xAA)
{
fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1;
}
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
{
//may want to mute this again, or may not want to
opts->unmute_encrypted_p25 = 0;
}
fprintf (stderr, "%s", KNRM);
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
state->payload_miP = (mihex1 << 32) | (mihex2);
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " ENC");
fprintf (stderr, "%s", KNRM);
}
fprintf (stderr, "\n");
}
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " ENC \n");
fprintf (stderr, "%s", KNRM);
}
if (opts->p25enc == 1 && opts->payload == 0)
{
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
}
if (opts->p25lc == 1)
{
fprintf (stderr, "mfid: %s tgid: %s ", mfid, tgid);
if (opts->p25tg == 0)
{
fprintf (stderr, "\n");
}
}
j = 0;
if (strcmp (mfid, "10010000") == 0)
{
for (i = 4; i < 16; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = tgid[i];
}
tmpstr[j] = tgid[i];
j++;
}
tmpstr[12] = '0';
tmpstr[13] = '0';
tmpstr[14] = '0';
tmpstr[15] = '0';
}
else
{
for (i = 0; i < 16; i++)
{
if (state->tgcount < 24)
{
state->tg[state->tgcount][j] = tgid[i];
}
tmpstr[j] = tgid[i];
j++;
}
}
tmpstr[16] = 0;
talkgroup = strtol (tmpstr, NULL, 2);
state->lasttg = talkgroup;
if (state->tgcount < 24)
{
state->tgcount = state->tgcount + 1;
}
if (opts->p25tg == 1)
{
fprintf (stderr, "tg: %li\n", talkgroup);
}
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " HDU FEC ERR \n");
fprintf (stderr, "%s", KNRM);
}
}

View File

@@ -171,6 +171,8 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
// TODO: error correction of the LSD bytes...
// TODO: do something useful with the LSD bytes...
state->dropL += 2; //need to skip 2 here for the LSD bytes
}
// IMBE 9
@@ -324,15 +326,53 @@ processLDU1 (dsd_opts* opts, dsd_state* state)
lcinfo[54] = hex_data[ 0][4] + '0';
lcinfo[55] = hex_data[ 0][5] + '0';
unsigned long long int lcinfohex = 0;
if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, otherwise, garbage values may be collected
{
state->payload_mfid = strtol (mfid, NULL, 2);
int j;
uint8_t LCW_bytes[9];
uint8_t LCW_bits[72];
memset (LCW_bytes, 0, sizeof(LCW_bytes));
memset (LCW_bits, 0, sizeof(LCW_bits));
//state->payload_mfid = ConvertBitIntoBytes(&mfid[0], 7);
lcinfohex = ConvertBitIntoBytes(&lcinfo[0], 55);
//fprintf (stderr, " LDU1 LCINFO %16llX \n", lcinfohex);
//load array above into byte form first
LCW_bytes[0] = (uint8_t) ConvertBitIntoBytes(&lcformat[0], 8);
LCW_bytes[1] = (uint8_t) ConvertBitIntoBytes(&mfid[0], 8);
for (i = 0; i < 7; i++) LCW_bytes[i+2] = (uint8_t) ConvertBitIntoBytes(&lcinfo[i*8], 8);
//load as bit array next (easier to process data in bit form)
for(i = 0, j = 0; i < 9; i++, j+=8)
{
LCW_bits[j + 0] = (LCW_bytes[i] >> 7) & 0x01;
LCW_bits[j + 1] = (LCW_bytes[i] >> 6) & 0x01;
LCW_bits[j + 2] = (LCW_bytes[i] >> 5) & 0x01;
LCW_bits[j + 3] = (LCW_bytes[i] >> 4) & 0x01;
LCW_bits[j + 4] = (LCW_bytes[i] >> 3) & 0x01;
LCW_bits[j + 5] = (LCW_bytes[i] >> 2) & 0x01;
LCW_bits[j + 6] = (LCW_bytes[i] >> 1) & 0x01;
LCW_bits[j + 7] = (LCW_bytes[i] >> 0) & 0x01;
}
//send to new P25 LCW function
if (irrecoverable_errors == 0)
{
fprintf (stderr, "%s", KYEL);
p25_lcw (opts, state, LCW_bits, 0);
fprintf (stderr, "%s", KNRM);
}
else
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " LCW FEC ERR ");
fprintf (stderr, "%s\n", KNRM);
}
processP25lcw (opts, state, lcformat, mfid, lcinfo);
if (opts->payload == 1)
{
fprintf (stderr, "%s",KCYN);
fprintf (stderr, " P25 LCW Payload ");
for (i = 0; i < 9; i++)
{
fprintf (stderr, "[%02X]", LCW_bytes[i]);
}
fprintf (stderr, "%s\n", KNRM);
}
}

View File

@@ -172,6 +172,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
// TODO: error correction of the LSD bytes...
// TODO: do something useful with the LSD bytes...
state->dropL += 2; //need to skip 2 here for the LSD bytes
}
// IMBE 9
@@ -183,6 +185,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
//set vc counter to 0
state->p25vc = 0;
//reset dropbytes -- skip first 11 for next LCW
state->dropL = 267;
if (opts->errorbars == 1)
{
fprintf (stderr, "\n");
@@ -357,37 +362,87 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
kid[14] = hex_data[ 0][4] + '0';
kid[15] = hex_data[ 0][5] + '0';
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
//if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors??
if (state->carrier == 1)
if (irrecoverable_errors == 0)
{
algidhex = strtol (algid, NULL, 2);
kidhex = strtol (kid, NULL, 2);
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%04X MI: 0x%08llX%08llX", algidhex, kidhex, mihex1, mihex2);
state->payload_algid = algidhex;
state->payload_keyid = kidhex;
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
if (state->R != 0 && state->payload_algid == 0xAA)
{
fprintf (stderr, " Key: %010llX", state->R);
opts->unmute_encrypted_p25 = 1;
}
else if (state->payload_algid != 0 && state->payload_algid != 0x80)
{
//may want to mute this again, or may not want to
opts->unmute_encrypted_p25 = 0;
}
fprintf (stderr, "%s", KNRM);
//only use 64 MSB, trailing 8 bits aren't used, so no mihex3
state->payload_miP = (mihex1 << 32) | (mihex2);
if (state->payload_algid != 0x80 && state->payload_algid != 0x0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " ENC");
fprintf (stderr, "%s", KNRM);
}
fprintf (stderr, "\n");
}
else
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " LDU2 FEC ERR \n");
fprintf (stderr, "%s", KNRM);
}
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
//run LFSR on the MI if we have irrecoverable errors here
if (irrecoverable_errors && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3);
fprintf (stderr, "%s", KNRM);
}
if (state->payload_algid != 0x80 && state->payload_algid != 0x0) //print on payload == 1
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " ENC \n");
fprintf (stderr, "%s", KNRM);
LFSRP(state);
fprintf (stderr, "\n");
}
}
//LFSR code courtesy of https://github.com/mattames/LFSR/
void LFSRP(dsd_state * state)
{
//rework for P2 TDMA support
unsigned long long int lfsr = 0;
if (state->currentslot == 0)
lfsr = state->payload_miP;
if (state->currentslot == 1)
lfsr = state->payload_miN;
int cnt = 0;
for(cnt=0;cnt<64;cnt++)
{
// Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
unsigned long long int bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1;
lfsr = (lfsr << 1) | (bit);
}
if (state->currentslot == 0)
state->payload_miP = lfsr;
if (state->currentslot == 1)
state->payload_miN = lfsr;
//print current ENC identifiers already known and new calculated MI
fprintf (stderr, "%s", KYEL);
if (state->currentslot == 0)
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algid, state->payload_keyid, state->payload_miP);
if (state->currentslot == 1)
fprintf (stderr, " LDU2/ESS_B FEC ERR - ALG: 0x%02X KEY ID: 0x%04X LFSR MI: 0x%016llX", state->payload_algidR, state->payload_keyidR, state->payload_miN);
fprintf (stderr, "%s", KNRM);
}

534
src/p25p1_mdpu.c Normal file
View File

@@ -0,0 +1,534 @@
/*-------------------------------------------------------------------------------
* p25p1_mpdu.c
* P25p1 Multi Block PDU and Multi Block Trunking
*
* LWVMOBILE
* 2023-03 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
#include "dsd.h"
static uint32_t crc32mbf(uint8_t buf[], int len)
{
uint32_t g = 0x04c11db7;
uint64_t crc = 0;
for (int i = 0; i < len; i++)
{
crc <<= 1;
int b = ( buf [i / 8] >> (7 - (i % 8)) ) & 1;
if (((crc >> 32) ^ b) & 1) crc ^= g;
}
crc = (crc & 0xffffffff) ^ 0xffffffff;
return crc;
}
void processMPDU(dsd_opts * opts, dsd_state * state)
{
//reset some strings when returning from a call in case they didn't get zipped already
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//clear stale Active Channel messages here
if ( (time(NULL) - state->last_active_time) > 3 )
{
memset (state->active_channel, 0, sizeof(state->active_channel));
}
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
int tsbk_dibit[98];
memset (tsbkbit, 0, sizeof(tsbkbit));
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
int dibit = 0;
uint8_t tsbk_byte[12]; //12 byte return from bd_bridge (block_deinterleave)
memset (tsbk_byte, 0, sizeof(tsbk_byte));
unsigned long long int PDU[24];
memset (PDU, 0, sizeof(PDU));
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
uint8_t mpdu_decoded_bits[288];
memset (mpdu_decoded_bits, 0, sizeof(mpdu_decoded_bits));
uint8_t mpdu_crc_bits[196];
memset (mpdu_crc_bits, 0, sizeof(mpdu_crc_bits));
uint8_t mpdu_crc_bytes[24];
memset (mpdu_crc_bytes, 0, sizeof(mpdu_crc_bytes));
int flushing_bits[196]; //for flushing the trellis state machine
memset (flushing_bits, 0, sizeof(flushing_bits));
int i, j, k, b, x, y;
int ec[3]; //error value returned from (block_deinterleave)
int err[2]; //error value returned from ccrc16 or crc32
memset (ec, -2, sizeof(ec));
memset (err, -2, sizeof(err));
int skipdibit = 14; //initial status dibit will occur at 14, then add 36 each time it occurs
int protectbit = 0;
int MFID = 0xFF; //Manufacturer ID
uint8_t mpdu_byte[36];
memset (mpdu_byte, 0, sizeof(mpdu_byte));
uint8_t io = 0;
uint8_t fmt = 0;
uint8_t sap = 0;
uint8_t blks = 0;
uint8_t opcode = 0;
//CRC32
uint32_t CRCComputed = 0;
uint32_t CRCExtracted = 0;
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
for (j = 0; j < 3; j++)
{
k = 0;
for (i = 0; i < 101; i++)
{
dibit = getDibit(opts, state);
if (i+(j*101) != skipdibit) //
{
tsbk_dibit[k] = dibit;
tsbkbit[k*2] = (dibit >> 1) & 1;
tsbkbit[k*2+1] = (dibit & 1);
k++;
}
if (i+(j*101) == skipdibit)
{
skipdibit += 36; //was set to 35, this was the bug
}
}
//flushing the trellis state machine
if (j == 0)
{
bd_bridge(flushing_bits, tsbk_byte);
//reset tsbk_byte afterwards
memset (tsbk_byte, 0, sizeof(tsbk_byte));
}
//send tsbkbit to block_deinterleave and return tsbk_byte
ec[j] = bd_bridge(tsbkbit, tsbk_byte);
//too many bit manipulations!
k = 0;
for (i = 0; i < 12; i++)
{
for (x = 0; x < 8; x++)
{
tsbk_decoded_bits[k] = ((tsbk_byte[i] << x) & 0x80) >> 7;
k++;
}
}
//CRC16 on the header
if (j == 0) err[0] = crc16_lb_bridge(tsbk_decoded_bits, 80);
//load into bit array for storage (easier decoding for future PDUs)
for (i = 0; i < 96; i++) mpdu_decoded_bits[i+(j*96)] = (uint8_t)tsbk_decoded_bits[i];
//shuffle corrected bits back into tsbk_byte
k = 0;
for (i = 0; i < 12; i++)
{
int byte = 0;
for (x = 0; x < 8; x++)
{
byte = byte << 1;
byte = byte | tsbk_decoded_bits[k];
k++;
}
tsbk_byte[i] = byte;
mpdu_byte[i+(j*12)] = byte; //add to completed MBF format bytes
}
}
io = (mpdu_byte[0] >> 5) & 0x1;
fmt = mpdu_byte[0] & 0x1F;
sap = mpdu_byte[1] & 0x3F;
blks = mpdu_byte[6] & 0x7F;
MFID = mpdu_byte[2];
//group list mode so we can look and see if we need to block tuning any groups, etc
char mode[8]; //allow, block, digital, enc, etc
sprintf (mode, "%s", "");
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
fprintf (stderr, "%s",KGRN);
fprintf (stderr, " P25 MBF FMT: %02X SAP: %02X", fmt, sap);
fprintf (stderr, " Blocks: %02X MFID: %02X", blks, MFID);
//trunking blocks
if ((sap == 0x3D) && ((fmt == 0x17) || (fmt == 0x15)))
{
if (fmt == 0x15) fprintf (stderr, " UNC");
else fprintf (stderr, " ALT");
fprintf (stderr, " MBT"); //find way to convert to vPDU or TSBK format?
if (fmt == 0x17) opcode = mpdu_byte[7] & 0x3F; //alt MBT
else opcode = mpdu_byte[12] & 0x3F; //unconf MBT
fprintf (stderr, " - OP: %02X", opcode);
}
//CRC32 is now working!
for (i = 0; i < 196; i++) mpdu_crc_bits[i] = mpdu_decoded_bits[i+96];
for (i = 0; i < 24; i++) mpdu_crc_bytes[i] = mpdu_byte[i+12];
if (blks == 1) //blocks to follow is 1
{
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&mpdu_crc_bits[96-32], 32);
CRCComputed = crc32mbf(mpdu_crc_bytes, 96-32);
if (CRCComputed == CRCExtracted) err[1] = 0;
}
if (blks == 2) //blocks to follow is 2
{
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&mpdu_crc_bits[192-32], 32);
CRCComputed = crc32mbf(mpdu_crc_bytes, 192-32);
if (CRCComputed == CRCExtracted) err[1] = 0;
}
//just going to do a couple for now -- the extended format will not be vPDU compatible :(
if (err[0] == 0 && err[1] == 0 && io == 1 && fmt == 0x17) //ALT Format
{
//NET_STS_BCST -- TIA-102.AABC-D 6.2.11.2
if (opcode == 0x3B)
{
int lra = mpdu_byte[3];
int sysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
int res_a = mpdu_byte[8];
int res_b = mpdu_byte[9];
long int wacn = (mpdu_byte[12] << 12) | (mpdu_byte[13] << 4) | (mpdu_byte[14] >> 4);
int channelt = (mpdu_byte[15] << 8) | mpdu_byte[16];
int channelr = (mpdu_byte[17] << 8) | mpdu_byte[18];
int ssc = mpdu_byte[19];
fprintf (stderr, "%s",KYEL);
fprintf (stderr, "\n Network Status Broadcast MBT - Extended \n");
fprintf (stderr, " LRA [%02X] WACN [%05lX] SYSID [%03X] NAC [%03llX]\n", lra, wacn, sysid, state->p2_cc);
fprintf (stderr, " CHAN-T [%04X] CHAN-R [%04X]", channelt, channelr);
long int ct_freq = process_channel_to_freq(opts, state, channelt);
long int cr_freq = process_channel_to_freq(opts, state, channelr);
state->p25_cc_freq = ct_freq;
state->p25_cc_is_tdma = 0; //flag off for CC tuning purposes when system is qpsk
//place the cc freq into the list at index 0 if 0 is empty, or not the same,
//so we can hunt for rotating CCs without user LCN list
if (state->trunk_lcn_freq[0] == 0 || state->trunk_lcn_freq[0] != state->p25_cc_freq)
{
state->trunk_lcn_freq[0] = state->p25_cc_freq;
}
//only set IF these values aren't already hard set by the user
if (state->p2_hardset == 0)
{
state->p2_wacn = wacn;
state->p2_sysid = sysid;
}
}
//RFSS Status Broadcast - Extended 6.2.15.2
else if (opcode == 0x3A)
{
int lra = mpdu_byte[3];
int lsysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
int rfssid = mpdu_byte[12];
int siteid = mpdu_byte[13];
int channelt = (mpdu_byte[14] << 8) | mpdu_byte[15];
int channelr = (mpdu_byte[16] << 8) | mpdu_byte[17];
int sysclass = mpdu_byte[18];
fprintf (stderr, "%s",KYEL);
fprintf (stderr, "\n RFSS Status Broadcast MBF - Extended \n");
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X]\n CHAN-T [%04X] CHAN-R [%02X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channelt, channelr, sysclass);
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
state->p2_siteid = siteid;
state->p2_rfssid = rfssid;
}
//Adjacent Status Broadcast (ADJ_STS_BCST) Extended 6.2.2.2
else if (opcode == 0x3C)
{
int lra = mpdu_byte[3];
int cfva = mpdu_byte[4] >> 4;
int lsysid = ((mpdu_byte[4] & 0xF) << 8) | mpdu_byte[5];
int rfssid = mpdu_byte[8];
int siteid = mpdu_byte[9];
int channelt = (mpdu_byte[12] << 8) | mpdu_byte[13];
int channelr = (mpdu_byte[14] << 8) | mpdu_byte[15];
int sysclass = mpdu_byte[16];
long int wacn = (mpdu_byte[17] << 12) | (mpdu_byte[18] << 4) | (mpdu_byte[19] >> 4);
fprintf (stderr, "%s",KYEL);
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
fprintf (stderr, " LRA [%02X] CFVA [%X] RFSS[%03d] SYSID [%03X] SITE [%03X]\n CHAN-T [%04X] CHAN-R [%04X] SSC [%02X] WACN [%05lX]\n ", lra, cfva, rfssid, lsysid, siteid, channelt, channelr, sysclass, wacn);
if (cfva & 0x8) fprintf (stderr, " Conventional");
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
else fprintf (stderr, " Last Known");
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
}
//Group Voice Channel Grant - Extended
else if (opcode == 0x0)
{
int svc = mpdu_byte[8];
int channelt = (mpdu_byte[14] << 8) | mpdu_byte[15];
int channelr = (mpdu_byte[16] << 8) | mpdu_byte[17];
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
int group = (mpdu_byte[18] << 8) | mpdu_byte[19];
long int freq1 = 0;
long int freq2 = 0;
fprintf (stderr, "%s\n ",KYEL);
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Group Voice Channel Grant Update - Extended");
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
freq1 = process_channel_to_freq (opts, state, channelt);
freq2 = process_channel_to_freq (opts, state, channelr);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d ", channelt, group);
state->last_active_time = time(NULL);
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == group)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (svc & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
//tune if tuning available
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
{
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
// if (opts->mod_qpsk == 1)
// {
// int spacing = state->p25_chan_spac[channelt >> 12];
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
// {
// state->samplesPerSymbol = 8;
// state->symbolCenter = 3;
// }
// }
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
if (state->p25_chan_tdma[channelt >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
//rigctl
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
}
//Unit to Unit Voice Channel Grant - Extended
else if (opcode == 0x6)
{
//I'm not doing EVERY element of this, just enough for tuning!
int svc = mpdu_byte[8];
int channelt = (mpdu_byte[22] << 8) | mpdu_byte[23];
int channelr = (mpdu_byte[24] << 8) | mpdu_byte[25]; //optional!
//using source and target address, not source and target id (is this correct?)
long int source = (mpdu_byte[3] << 16) |(mpdu_byte[4] << 8) | mpdu_byte[5];
long int target = (mpdu_byte[19] << 16) |(mpdu_byte[20] << 8) | mpdu_byte[21];
long int freq1 = 0;
long int freq2 = 0;
fprintf (stderr, "%s\n ",KYEL);
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Unit to Unit Voice Channel Grant Update - Extended");
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Source [%ld][%04lX] Target [%ld][%04lX]", svc, channelt, channelr, source, source, target, target);
freq1 = process_channel_to_freq (opts, state, channelt);
freq2 = process_channel_to_freq (opts, state, channelr); //optional!
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TGT: %ld; ", channelt, target);
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == target)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//Skip tuning private calls if group calls are disabled
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (svc & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
//tune if tuning available
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
{
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
// if (opts->mod_qpsk == 1)
// {
// int spacing = state->p25_chan_spac[channelt >> 12];
// if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
// {
// state->samplesPerSymbol = 8;
// state->symbolCenter = 3;
// }
// }
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
if (state->p25_chan_tdma[channelt >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
//rigctl
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl
else if (opts->audio_in_type == 3)
{
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
}
else
{
//convert mpdu_byte to vPDU format and get indication of what the message was
PDU[0] = 0x0C; //P25p1 MB Duid 0x0C
PDU[1] = opcode;
PDU[2] = MFID;
PDU[1] = PDU[1] ^ 0xC0; //flip bits to make it compatible with MAC_PDUs explicit format
//without any extra bytes filled in, we can atleast see what the MBT is supposed to be
//Hopefully, no 0 value things will cause issues -- call grants, iden_up, etc!
// fprintf (stderr, "%s",KYEL);
// process_MAC_VPDU(opts, state, 0, PDU);
// fprintf (stderr, "%s",KNRM);
}
}
SKIPCALL: ; //do nothing
if (opts->payload == 1)
{
fprintf (stderr, "%s",KCYN);
fprintf (stderr, "\n P25 MBF Payload \n ");
for (i = 0; i < 36; i++)
{
fprintf (stderr, "[%02X]", mpdu_byte[i]);
if (i == 11 || i == 23) fprintf (stderr, "\n ");
}
fprintf (stderr, " CRC EXT %08X CMP %08X", CRCExtracted, CRCComputed);
fprintf (stderr, "%s ", KNRM);
fprintf (stderr, "\n ");
//Header
if (err[0] != 0)
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " (HDR CRC16 ERR)");
fprintf (stderr, "%s",KCYN);
}
//Completed MBF
if (err[1] != 0)
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " (MBF CRC32 ERR)");
fprintf (stderr, "%s",KCYN);
}
}
fprintf (stderr, "%s ", KNRM);
fprintf (stderr, "\n");
}

View File

@@ -33,4 +33,13 @@ processTDU (dsd_opts* opts, dsd_state* state)
status = getDibit (opts, state) + '0';
// TODO: do something useful with the status bits...
}
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//zero out on termination
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_miP = 0;
}

View File

@@ -390,11 +390,65 @@ processTDULC (dsd_opts* opts, dsd_state* state)
lcinfo[53] = dodeca_data[0][ 9] + '0';
lcinfo[54] = dodeca_data[0][10] + '0';
lcinfo[55] = dodeca_data[0][11] + '0';
/*
if (state->carrier == 1) //only update when carrier is present, otherwise, garbage values may be collected
int j;
uint8_t LCW_bytes[9];
uint8_t LCW_bits[72];
memset (LCW_bytes, 0, sizeof(LCW_bytes));
memset (LCW_bits, 0, sizeof(LCW_bits));
//load array above into byte form first
LCW_bytes[0] = (uint8_t) ConvertBitIntoBytes(&lcformat[0], 8);
LCW_bytes[1] = (uint8_t) ConvertBitIntoBytes(&mfid[0], 8);
for (i = 0; i < 7; i++) LCW_bytes[i+2] = (uint8_t) ConvertBitIntoBytes(&lcinfo[i*8], 8);
//load as bit array next (easier to process data in bit form)
for(i = 0, j = 0; i < 9; i++, j+=8)
{
state->payload_mfid = strtol (mfid, NULL, 2); //wonder if this is accurate info or not
LCW_bits[j + 0] = (LCW_bytes[i] >> 7) & 0x01;
LCW_bits[j + 1] = (LCW_bytes[i] >> 6) & 0x01;
LCW_bits[j + 2] = (LCW_bytes[i] >> 5) & 0x01;
LCW_bits[j + 3] = (LCW_bytes[i] >> 4) & 0x01;
LCW_bits[j + 4] = (LCW_bytes[i] >> 3) & 0x01;
LCW_bits[j + 5] = (LCW_bytes[i] >> 2) & 0x01;
LCW_bits[j + 6] = (LCW_bytes[i] >> 1) & 0x01;
LCW_bits[j + 7] = (LCW_bytes[i] >> 0) & 0x01;
}
*/
processP25lcw (opts, state, lcformat, mfid, lcinfo);
//send to new P25 LCW function
if (irrecoverable_errors == 0)
{
fprintf (stderr, "%s", KYEL);
p25_lcw (opts, state, LCW_bits, 0);
fprintf (stderr, "%s", KNRM);
}
else
{
fprintf (stderr, "%s",KRED);
fprintf (stderr, " LCW FEC ERR ");
fprintf (stderr, "%s\n", KNRM);
}
if (opts->payload == 1)
{
fprintf (stderr, "%s",KCYN);
fprintf (stderr, " P25 LCW Payload ");
for (i = 0; i < 9; i++)
{
fprintf (stderr, "[%02X]", LCW_bytes[i]);
}
fprintf (stderr, "%s\n", KNRM);
}
//reset some strings -- since its a tdu, blank out any call strings, only want during actual call
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//zero out on termination
state->payload_algid = 0;
state->payload_keyid = 0;
state->payload_miP = 0;
}

View File

@@ -8,82 +8,39 @@
#include "dsd.h"
int block_convolution (int payload[196], uint8_t decoded[12])
{
int ec = -1; //initialize error value
uint8_t deinterleaved_bits[196];
uint8_t trellis_bytes[12];
uint8_t m_data[14];
uint8_t temp[210]; //temp bit position buffer for convolution
//initialize our deinterleaved bits and bytes with zeroes
for (int i = 0; i < 196; i++) deinterleaved_bits[i] = 0;
for (int i = 0; i < 210; i++) temp[i] = 0;
for (int i = 0; i < 12; i++) trellis_bytes[i] = 0;
for (int i = 0; i < 14; i++) m_data[i] = 0;
//convolution decoder
uint8_t s0;
uint8_t s1;
//initialize our decoded byte buffer with zeroes
for (int i = 0; i < 12; i++) decoded[i] = 0;
static const uint16_t deinterleave_tsbk[] = {
0, 1, 2, 3, 52, 53, 54, 55, 100,101,102,103, 148,149,150,151,
4, 5, 6, 7, 56, 57, 58, 59, 104,105,106,107, 152,153,154,155,
8, 9, 10, 11, 60, 61, 62, 63, 108,109,110,111, 156,157,158,159,
12, 13, 14, 15, 64, 65, 66, 67, 112,113,114,115, 160,161,162,163,
16, 17, 18, 19, 68, 69, 70, 71, 116,117,118,119, 164,165,166,167,
20, 21, 22, 23, 72, 73, 74, 75, 120,121,122,123, 168,169,170,171,
24, 25, 26, 27, 76, 77, 78, 79, 124,125,126,127, 172,173,174,175,
28, 29, 30, 31, 80, 81, 82, 83, 128,129,130,131, 176,177,178,179,
32, 33, 34, 35, 84, 85, 86, 87, 132,133,134,135, 180,181,182,183,
36, 37, 38, 39, 88, 89, 90, 91, 136,137,138,139, 184,185,186,187,
40, 41, 42, 43, 92, 93, 94, 95, 140,141,142,143, 188,189,190,191,
44, 45, 46, 47, 96, 97, 98, 99, 144,145,146,147, 192,193,194,195,
48, 49, 50, 51 };
//get the deinterleaved bits
for (int i = 0; i < 196; i++) deinterleaved_bits[deinterleave_tsbk[i]] = payload[i];
//shift into proper position for the convolutional decoder
for (int i = 0; i < 196; i++) temp[i] = deinterleaved_bits[i] << 1;
CNXDNConvolution_start();
for (int i = 0U; i < 98U; i++) //102U
{
s0 = temp[(2*i)];
s1 = temp[(2*i)+1];
CNXDNConvolution_decode(s0, s1);
}
CNXDNConvolution_chainback(m_data, 96U); //98U
//debug print
fprintf (stderr, "\n Convolution Chainback - ");
for (int i = 0; i < 14; i++) fprintf (stderr, "[%02X]", m_data[i]);
//transfer m_data to decoded bytes -- when sorted out, can probably send decoded straight to chainback, and save the code
// for (int i = 0; i < 12; i++) decoded[i] = m_data[i];
ec = 0; //unknown if a method exists to returns errors from the convolutional decoder, just rely on CRC check for now
return ec;
}
void processTSBK(dsd_opts * opts, dsd_state * state)
{
//reset some strings when returning from a call in case they didn't get zipped already
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//clear stale Active Channel messages here
if ( (time(NULL) - state->last_active_time) > 3 )
{
memset (state->active_channel, 0, sizeof(state->active_channel));
}
int tsbkbit[196] = {0}; //tsbk bit array, 196 trellis encoded bits
int tsbk_dibit[98] = {0};
int tsbkbit[196]; //tsbk bit array, 196 trellis encoded bits
int tsbk_dibit[98];
memset (tsbkbit, 0, sizeof(tsbkbit));
memset (tsbk_dibit, 0, sizeof(tsbk_dibit));
int dibit = 0;
uint8_t tsbk_byte[12] = {0}; //12 byte return from bd_bridge (block_deinterleave)
unsigned long long int PDU[24] = {0}; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
int tsbk_decoded_bits[190] = {0}; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
uint8_t tsbk_byte[12]; //12 byte return from bd_bridge (block_deinterleave)
memset (tsbk_byte, 0, sizeof(tsbk_byte));
unsigned long long int PDU[24]; //24 byte PDU to send to the tsbk_byte vPDU handler, should be same formats (mostly)
memset (PDU, 0, sizeof(PDU));
int tsbk_decoded_bits[190]; //decoded bits from tsbk_bytes for sending to crc16_lb_bridge
memset (tsbk_decoded_bits, 0, sizeof(tsbk_decoded_bits));
int flushing_bits[196]; //for flushing the trellis state machine
memset (flushing_bits, 0, sizeof(flushing_bits));
int i, j, k, b, x, y;
int ec = -2; //error value returned from (block_deinterleave)
int err = -2; //error value returned from crc16_lb_bridge
@@ -91,11 +48,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
int protectbit = 0;
int MFID = 0xFF; //Manufacturer ID - Might be beneficial to NOT send anything but standard 0x00 or 0x01 messages
//Update: Identified Bug in skipdibit incrememnt causing many block deinterleave/crc failures
//with correct values set, now we are decoding many more TSBKs
//TODO: Don't Print TSBKs/vPDUs unless verbosity levels set higher
//TSBKs are always single block, but up to three can be transmitted in a row,
//Multi-Block PDUs are sent on a different DUID - 0xC (not handled currently)
//collect three reps of 101 dibits (98 valid dibits with status dibits interlaced)
for (j = 0; j < 3; j++)
@@ -116,13 +69,18 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
if (i+(j*101) == skipdibit)
{
skipdibit += 36; //was set to 35, this was the bug
skipdibit += 36;
}
}
//test with the nxdn convolutional decoder
// ec = block_convolution (tsbkbit, tsbk_byte);
//flushing the trellis state machine
if (j == 0)
{
bd_bridge(flushing_bits, tsbk_byte);
//reset tsbk_byte afterwards
memset (tsbk_byte, 0, sizeof(tsbk_byte));
}
//send tsbkbit to block_deinterleave and return tsbk_byte
ec = bd_bridge(tsbkbit, tsbk_byte);
@@ -178,7 +136,9 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
//Don't run NET_STS out of this, or will set wrong NAC/CC //&& PDU[1] != 0x49 && PDU[1] != 0x45
//0x49 is telephone grant, 0x46 Unit to Unit Channel Answer Request (seems bogus) (mfid 90)
// if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
if ( (MFID < 0x2 || MFID == 0xA4 || MFID == 0x90) && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
//running with A4 and 90 causing some false positives when sending to vPDU, issuing bad call grants to nowhere!
// if ( (MFID < 0x2 || MFID == 0xA4 || MFID == 0x90) && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
if (MFID < 0x2 && protectbit == 0 && err == 0 && ec == 0 && PDU[1] != 0x7B )
{
fprintf (stderr, "%s",KYEL);
process_MAC_VPDU(opts, state, 0, PDU);
@@ -188,7 +148,7 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
//set our WACN and SYSID here now that we have valid ec and crc/checksum
else if (protectbit == 0 && err == 0 && ec == 0 && (tsbk_byte[0] & 0x3F) == 0x3B)
{
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);;
long int wacn = (tsbk_byte[3] << 12) | (tsbk_byte[4] << 4) | (tsbk_byte[5] >> 4);
int sysid = ((tsbk_byte[5] & 0xF) << 8) | tsbk_byte[6];
int channel = (tsbk_byte[7] << 8) | tsbk_byte[8];
fprintf (stderr, "%s",KYEL);

View File

@@ -75,7 +75,7 @@ int dibit = 0;
int vc_counter = 0;
int framing_counter = 0;
unsigned long long int isch = 0;
uint64_t isch = 0;
int isch_decoded = -1;
int p2_duid[8] = {0};
int16_t duid_decoded = 0;
@@ -475,10 +475,16 @@ void process_4V (dsd_opts * opts, dsd_state * state)
fprintf (stderr, "\n");
}
//set to 16 for MBE OSS shim to preempt audio
if (state->currentslot == 0) state->dmrburstL = 16;
else state->dmrburstR = 16;
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
//Cygwin OSS Slot Preference Pre-emption shim
if (opts->audio_out_type == 5)
{
//set to 21 for MBE OSS shim to preempt audio
if (state->currentslot == 0) state->dmrburstL = 21;
else state->dmrburstR = 21;
}
#endif
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
@@ -546,6 +552,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " ALG ID 0x%02X", state->payload_algid);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
fprintf (stderr, " ESSB");
}
@@ -561,6 +568,7 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
fprintf (stderr, " ALG ID 0x%02X", state->payload_algidR);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
fprintf (stderr, " ESSB");
}
@@ -568,7 +576,11 @@ void process_ESS (dsd_opts * opts, dsd_state * state)
}
if (ec == -1 || ec >= 15)
{
//ESS R-S Failure
//ESS R-S Failure -- run LFSR on current MI if applicable
if (state->currentslot == 0 && state->payload_algid != 0x80 && state->payload_keyid != 0 && state->payload_miP != 0)
LFSRP(state);
if (state->currentslot == 1 && state->payload_algidR != 0x80 && state->payload_keyidR != 0 && state->payload_miN != 0)
LFSRP(state);
}
fprintf (stderr, "%s", KNRM);
@@ -630,15 +642,28 @@ void process_2V (dsd_opts * opts, dsd_state * state)
fprintf (stderr, "\n");
}
//set to 16 for MBE OSS shim to preempt audio
if (state->currentslot == 0) state->dmrburstL = 16;
else state->dmrburstR = 16;
#ifdef AERO_BUILD //FUN FACT: OSS stutters only on Cygwin, using padsp in linux, it actually opens two virtual /dev/dsp audio streams for output
//Cygwin OSS Slot Preference Pre-emption shim
if (opts->audio_out_type == 5)
{
//set to 21 for MBE OSS shim to preempt audio
if (state->currentslot == 0) state->dmrburstL = 21;
else state->dmrburstR = 21;
}
#endif
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
process_ESS(opts, state);
//reset drop bytes after a 2V
if (state->currentslot == 0 && state->payload_algid == 0xAA)
state->dropL = 256;
if (state->currentslot == 1 && state->payload_algidR == 0xAA)
state->dropR = 256;
}
//P2 Data Unit ID
@@ -711,12 +736,24 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
}
else fprintf (stderr, "VCH S ");
//check to see when last voice activity occurred in order to allow tuning on phase 2
//mac_signal or mac_idle when no more voice activity on current channel
//this is primarily a fix for TDMA control channels that carry voice (Duke P25)
//but may also allow for chain tuning without returning to the control channel <--may be problematic since we can assign a p25_cc_freq from the pdu
if (duid_decoded == 13 && opts->p25_is_tuned == 1 && ((time(NULL) - state->last_vc_sync_time) > opts->trunk_hangtime) ) //version for MAC_SIGNAL only, no idle
{
opts->p25_is_tuned = 0;
state->p25_vc_freq[0] = state->p25_vc_freq[1] = 0;
memset (state->active_channel, 0, sizeof (state->active_channel)); //zero out here? I think this will be fine
}
if (duid_decoded == 0)
{
fprintf (stderr, " 4V %d", state->fourv_counter[state->currentslot]+1);
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
{
state->last_vc_sync_time = time(NULL);
process_4V (opts, state);
}
}
@@ -726,6 +763,7 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
if (state->p2_wacn != 0 && state->p2_cc != 0 && state->p2_sysid != 0 &&
state->p2_wacn != 0xFFFFF && state->p2_cc != 0xFFF && state->p2_sysid != 0xFFF)
{
state->last_vc_sync_time = time(NULL);
process_2V (opts, state);
}
}
@@ -823,22 +861,21 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
void processP2 (dsd_opts * opts, dsd_state * state)
{
state->dmr_stereo = 1;
//state->currentslot = 1;
p2_dibit_buffer (opts, state);
//look at our ISCH values and determine location in superframe before running frame scramble
for (framing_counter = 0; framing_counter < 4; framing_counter++) //12
for (framing_counter = 0; framing_counter < 4; framing_counter++)
{
process_ISCH (opts, state); //run ISCH in here so we know when to start descramble offset
//run ISCH in here so we know when to start descramble offset
process_ISCH (opts, state);
}
//set initial current slot depending on offset value
if (state->p2_scramble_offset % 2)
{
state->currentslot = 0;
state->currentslot = 1;
}
else state->currentslot = 1;
else state->currentslot = 0;
//frame_scramble runs lfsr and creates an array of unscrambled bits to pull from
process_Frame_Scramble (opts, state);
@@ -848,14 +885,5 @@ void processP2 (dsd_opts * opts, dsd_state * state)
state->dmr_stereo = 0;
state->p2_is_lcch = 0;
//bugfix for OSS dmrbust 16 shim, reset both to 0 upon exit
//in case or marginal signal and both get stuck on 16, indefinitely muting the non-preferred slot
//but...this can also cause at least one 4v/2v to get through on the other slot if the sync lines up that way
if (opts->audio_out_type == 5)
{
//set both to blank value
state->dmrburstL = 17;
state->dmrburstR = 17;
}
fprintf (stderr, "\n");
}

View File

@@ -76,6 +76,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//group list mode so we can look and see if we need to block tuning any groups, etc
char mode[8]; //allow, block, digital, enc, etc
sprintf (mode, "%s", "");
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
@@ -84,7 +85,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
for (int i = 0; i < 2; i++)
{
//MFID90 Voice Grants, A3, A4, and A5
//MFID90 Voice Grants, A3, A4, and A5 <--I bet A4 here was triggering a phantom call when TSBK sent PDUs here
//MFID90 Group Regroup Channel Grant - Implicit
if (MAC[1+len_a] == 0xA3 && MAC[2+len_a] == 0x90)
{
@@ -96,12 +97,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n CHAN [%04X] Group [%d][%04X]", channel, sgroup, sgroup);
freq = process_channel_to_freq (opts, state, channel);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; ", channel, sgroup);
state->last_active_time = time(NULL);
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == sgroup)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -114,30 +120,34 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[channel >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[channel >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
@@ -164,12 +174,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n CHAN [%04X] Group [%d][%04X]", channel, sgroup, sgroup);
freq = process_channel_to_freq (opts, state, channel);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d ", channel, sgroup);
state->last_active_time = time(NULL);
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == sgroup)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -182,15 +197,14 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[channel >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[channel >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
if (opts->use_rigctl == 1)
@@ -198,14 +212,18 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
@@ -239,6 +257,10 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
freq2 = process_channel_to_freq (opts, state, channel2);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "MFID90 Active Ch: %04X SG: %d; Ch: %04X SG: %d; ", channel1, group1, channel2, group2);
state->last_active_time = time(NULL);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
@@ -274,6 +296,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -283,16 +306,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[tunable_chan >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
@@ -300,17 +323,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
SetFreq(opts->rigctl_sockfd, tunable_freq);
//probably best to only set these when really tuning
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, tunable_freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, tunable_freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
#endif
}
}
}
@@ -339,38 +366,59 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
int source = (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | MAC[9+len_a];
long int freq = 0;
fprintf (stderr, "\n Group Voice Channel Grant Update");
fprintf (stderr, "\n");
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Group Voice Channel Grant Update");
fprintf (stderr, "\n SVC [%02X] CHAN [%04X] Group [%d] Source [%d]", svc, channel, group, source);
freq = process_channel_to_freq (opts, state, channel);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; ", channel, group);
state->last_active_time = time(NULL);
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == group)
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (svc & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
//tune if tuning available
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
{
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[channel >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[channel >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
@@ -378,13 +426,17 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
SetFreq(opts->rigctl_sockfd, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
@@ -403,7 +455,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
}
//Unit-to-Unit Voice Service Channel Grant (UU_V_CH_GRANT), or Grant Update (same format)
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46)
if (MAC[1+len_a] == 0x44 || MAC[1+len_a] == 0x46) //double check these opcodes
{
int channel = (MAC[2+len_a] << 8) | MAC[3+len_a];
int target = (MAC[4+len_a] << 16) | (MAC[5+len_a] << 8) | MAC[6+len_a];
@@ -415,9 +467,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n CHAN [%04X] Source [%d] Target [%d]", channel, source, target);
freq = process_channel_to_freq (opts, state, channel);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TGT: %d; ", channel, target);
state->last_active_time = time(NULL);
//Skip tuning private calls if private calls is disabled
if (opts->trunk_tune_private_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled -- abb formats do not carry svc bits :(
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
//unit to unit needs work, may fail under certain conditions (first blocked, second allowed, etc) (labels should still work though)
for (int i = 0; i < state->group_tally; i++)
{
@@ -425,6 +484,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -434,30 +494,34 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[channel >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[channel >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq);
if (state->synctype == 0 || state->synctype == 1) state->p25_vc_freq[0] = freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq);
if (state->synctype == 0 || state->synctype == 1) state->p25_vc_freq[0] = freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
@@ -489,17 +553,46 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
long int freq1r = 0;
long int freq2t = 0;
long int freq2r = 0;
fprintf (stderr, "\n Group Voice Channel Grant Update Multiple - Explicit");
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc1, channelt1, channelr1, group1, group1);
if (svc1 & 0x80) fprintf (stderr, " Emergency");
if (svc1 & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc1 & 0x20) fprintf (stderr, " Duplex");
if (svc1 & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc1 & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc1 & 0x7); //call priority
}
freq1t = process_channel_to_freq (opts, state, channelt1);
freq1r = process_channel_to_freq (opts, state, channelr1);
if (channelr1 != 0 && channelr1 != 0xFFFF) freq1r = process_channel_to_freq (opts, state, channelr1);
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc2, channelt2, channelr2, group2, group2);
if (svc2 & 0x80) fprintf (stderr, " Emergency");
if (svc2 & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc2 & 0x20) fprintf (stderr, " Duplex");
if (svc2 & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc2 & 0x7); //call priority
}
freq1t = process_channel_to_freq (opts, state, channelt2);
freq1r = process_channel_to_freq (opts, state, channelr2);
if (channelr2 != 0 && channelr2 != 0xFFFF) freq1r = process_channel_to_freq (opts, state, channelr2);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channelt1, group1, channelt2, group2);
state->last_active_time = time(NULL);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (svc1 & 0x40) && (svc2 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
int loop = 1;
if (channelt2 == channelt2) loop = 1;
else loop = 2;
@@ -510,6 +603,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
for (int j = 0; j < loop; j++)
{
//test svc opts for enc to tune or skip
if (j == 0)
{
if ( (svc1 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
}
if (j == 1)
{
if (( svc2 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //skip to end
}
//assign our internal variables for check down on if to tune one freq/group or not
if (j == 0)
{
@@ -529,6 +632,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -538,15 +642,14 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[tunable_chan >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
if (opts->use_rigctl == 1)
@@ -554,16 +657,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, tunable_freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, tunable_freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, tunable_freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
#endif
}
}
}
@@ -581,7 +688,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
}
//Group Voice Channel Grant Update Multiple - Implicit
if (MAC[1+len_a] == 0x05) //wonder if this is MAC_SIGNAL only? Too long for a TSBK
if (MAC[1+len_a] == 0x05)
{
int so1 = MAC[2+len_a];
int channel1 = (MAC[3+len_a] << 8) | MAC[4+len_a];
@@ -598,15 +705,54 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n Group Voice Channel Grant Update Multiple - Implicit");
fprintf (stderr, "\n Channel 1 [%04X] Group 1 [%d][%04X]", channel1, group1, group1);
if (so1 & 0x80) fprintf (stderr, " Emergency");
if (so1 & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (so1 & 0x20) fprintf (stderr, " Duplex");
if (so1 & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (so1 & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", so1 & 0x7); //call priority
}
freq1 = process_channel_to_freq (opts, state, channel1);
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
if (so2 & 0x80) fprintf (stderr, " Emergency");
if (so2 & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (so2 & 0x20) fprintf (stderr, " Duplex");
if (so2 & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (so2 & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", so2 & 0x7); //call priority
}
freq2 = process_channel_to_freq (opts, state, channel2);
fprintf (stderr, "\n Channel 3 [%04X] Group 3 [%d][%04X]", channel3, group3, group3);
if (so3 & 0x80) fprintf (stderr, " Emergency");
if (so3 & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (so3 & 0x20) fprintf (stderr, " Duplex");
if (so3 & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (so3 & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", so3 & 0x7); //call priority
}
freq3 = process_channel_to_freq (opts, state, channel3);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2, channel3, group3);
state->last_active_time = time(NULL);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (so1 & 0x40) && (so2 & 0x40) && (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
int loop = 3;
long int tunable_freq = 0;
@@ -615,6 +761,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
for (int j = 0; j < loop; j++)
{
//test svc opts for enc to tune or skip
if (j == 0)
{
if ( (so1 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
}
if (j == 1)
{
if ( (so2 & 0x40) && opts->trunk_tune_enc_calls == 0) j++; //skip to next
}
if (j == 2)
{
if ( (so3 & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //skip to end
}
//assign our internal variables for check down on if to tune one freq/group or not
if (j == 0)
{
@@ -641,6 +801,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -650,16 +811,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[tunable_chan >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
@@ -667,17 +828,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
SetFreq(opts->rigctl_sockfd, tunable_freq);
//probably best to only set these when really tuning
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, tunable_freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, tunable_freq);
//probably best to only set these when really tuning
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
#endif
}
}
}
@@ -710,9 +875,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n Channel 2 [%04X] Group 2 [%d][%04X]", channel2, group2, group2);
freq2 = process_channel_to_freq (opts, state, channel2);
//add active channel to string for ncurses display
sprintf (state->active_channel[0], "Active Ch: %04X TG: %d; Ch: %04X TG: %d; ", channel1, group1, channel2, group2);
state->last_active_time = time(NULL);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled -- abb formats do not carry svc bits :(
if (opts->trunk_tune_enc_calls == 0) goto SKIPCALL; //enable, or disable?
int loop = 1;
if (channel1 == channel2) loop = 1;
else loop = 2;
@@ -743,6 +915,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
@@ -752,16 +925,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && tunable_freq != 0) //if we aren't already on a VC and have a valid frequency already
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[tunable_chan >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[tunable_chan >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
@@ -770,16 +943,20 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
//probably best to only set these when really tuning
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, tunable_freq);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, tunable_freq);
//probably best to only set these when really tuning
state->p25_vc_freq[0] = state->p25_vc_freq[1] = tunable_freq;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
j = 8; //break loop
#endif
}
}
}
@@ -806,15 +983,30 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
long int freq1 = 0;
long int freq2 = 0;
fprintf (stderr, "\n Group Voice Channel Grant Update - Explicit");
fprintf (stderr, "\n");
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Group Voice Channel Grant Update - Explicit");
fprintf (stderr, "\n SVC [%02X] CHAN-T [%04X] CHAN-R [%04X] Group [%d][%04X]", svc, channelt, channelr, group, group);
freq1 = process_channel_to_freq (opts, state, channelt);
freq2 = process_channel_to_freq (opts, state, channelr);
if (slot == 0)
{
state->lasttg = group;
}
else state->lasttgR = group;
if (channelr != 0 && channelr != 0xFFFF) freq2 = process_channel_to_freq (opts, state, channelr); //one system had this as channel 0xFFFF -- look up any particular meaning for that
//don't set the tg here, one multiple grant updates, will mess up the TG value on current call
// if (slot == 0)
// {
// state->lasttg = group;
// }
// else state->lasttgR = group;
for (int i = 0; i < state->group_tally; i++)
{
@@ -822,42 +1014,51 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
break;
}
}
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCALL;
//Skip tuning encrypted calls if enc calls are disabled
if ( (svc & 0x40) && opts->trunk_tune_enc_calls == 0) goto SKIPCALL;
//tune if tuning available
if (opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0) && (strcmp(mode, "B") != 0))
{
//reworked to set freq once on any call to process_channel_to_freq, and tune on that, independent of slot
if (state->p25_cc_freq != 0 && opts->p25_is_tuned == 0 && freq1 != 0) //if we aren't already on a VC and have a valid frequency
{
//testing switch to P2 channel symbol rate with qpsk enabled, we need to know if we are going to a TDMA channel or an FDMA channel
if (opts->mod_qpsk == 1)
//changed to allow symbol rate change on C4FM Phase 2 systems as well as QPSK
if (1 == 1)
{
int spacing = state->p25_chan_spac[channelt >> 12];
if (spacing == 0x64) //tdma should always be 0x64, and fdma should always be 0x32
if (state->p25_chan_tdma[channelt >> 12] == 1)
{
state->samplesPerSymbol = 8;
state->symbolCenter = 3;
}
}
}
//rigctl
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
state->last_vc_sync_time = time(NULL);
}
//rtl_udp
//rtl
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, freq1);
#ifdef USE_RTLSDR
rtl_dev_tune (opts, freq1);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq1;
opts->p25_is_tuned = 1;
state->last_vc_sync_time = time(NULL);
#endif
}
}
}
@@ -999,18 +1200,31 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
}
//identifier update VHF/UHF
if (MAC[1+len_a] == 0x74)
//identifier update VHF/UHF
if (MAC[1+len_a] == 0x74)
{
state->p25_chan_iden = MAC[2+len_a] >> 4;
int iden = state->p25_chan_iden;
state->p25_chan_type[iden] = 1;
int bw_vu = (MAC[2+len_a] & 0xF);
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
state->p25_base_freq[iden] = (MAC[6+len_a] << 24) | (MAC[7+len_a] << 16) | (MAC[8+len_a] << 8) | (MAC[9+len_a] << 0);
//this is causing more issues -- need a different way to check on this
// if (state->p25_chan_spac[iden] == 0x64) //tdma
// {
// state->p25_chan_type[iden] = 4; //
// state->p25_chan_tdma[iden] = 1; //
// }
// else //fdma
// {
// state->p25_chan_type[iden] = 1; //
// state->p25_chan_tdma[iden] = 0; //
// }
state->p25_chan_type[iden] = 1; //set as old values for now
state->p25_chan_tdma[iden] = 0; //set as old values for now
fprintf (stderr, "\n Identifier Update UHF/VHF\n");
fprintf (stderr, " Channel Identifier [%01X] BW [%01X] Transmit Offset [%04X]\n Channel Spacing [%03X] Base Frequency [%08lX] [%09ld]",
state->p25_chan_iden, bw_vu, state->p25_trans_off[iden], state->p25_chan_spac[iden], state->p25_base_freq[iden], state->p25_base_freq[iden] * 5);
@@ -1023,6 +1237,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
int iden = state->p25_chan_iden;
state->p25_chan_type[iden] = 1;
state->p25_chan_tdma[iden] = 0;
int bw = ((MAC[2+len_a] & 0xF) << 5) | ((MAC[3+len_a] & 0xF8) >> 2);
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
@@ -1038,6 +1253,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
state->p25_chan_iden = MAC[2+len_a] >> 4;
int iden = state->p25_chan_iden;
state->p25_chan_tdma[iden] = 1;
state->p25_chan_type[iden] = MAC[2+len_a] & 0xF;
state->p25_trans_off[iden] = (MAC[3+len_a] << 6) | (MAC[4+len_a] >> 2);
state->p25_chan_spac[iden] = ((MAC[4+len_a] & 0x3) << 8) | MAC[5+len_a];
@@ -1053,6 +1269,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
state->p25_chan_iden = MAC[3+len_a] >> 4;
int iden = state->p25_chan_iden;
state->p25_chan_tdma[iden] = 1;
state->p25_chan_type[iden] = MAC[3+len_a] & 0xF;
state->p25_trans_off[iden] = (MAC[4+len_a] << 6) | (MAC[5+len_a] >> 2);
state->p25_chan_spac[iden] = ((MAC[5+len_a] & 0x3) << 8) | MAC[6+len_a];
@@ -1079,7 +1296,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
{
fprintf (stderr, "\n Secondary Control Channel Broadcast - Explicit\n");
fprintf (stderr, " RFSS[%03d] SITE ID [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", rfssid, siteid, channelt, channelr, sysclass);
fprintf (stderr, " RFSS [%03d] SITE ID [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", rfssid, siteid, channelt, channelr, sysclass);
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
@@ -1223,7 +1440,25 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
int src = (MAC[5+len_a] << 16) | (MAC[6+len_a] << 8) | MAC[7+len_a];
fprintf (stderr, "\n VCH %d - TG %d SRC %d ", slot, gr, src);
fprintf (stderr, "Group Voice");
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Group Voice");
sprintf (state->call_string[slot], " Group ");
if (svc & 0x80) strcat (state->call_string[slot], " Emergency ");
else if (svc & 0x40) strcat (state->call_string[slot], " Encrypted ");
else strcat (state->call_string[slot], " ");
if (slot == 0)
{
@@ -1244,7 +1479,25 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
int src = (MAC[6+len_a] << 16) | (MAC[7+len_a] << 8) | MAC[8+len_a];
fprintf (stderr, "\n VCH %d - TG %d SRC %d ", slot, gr, src);
fprintf (stderr, "Unit to Unit Voice");
if (svc & 0x80) fprintf (stderr, " Emergency");
if (svc & 0x40) fprintf (stderr, " Encrypted");
if (opts->payload == 1) //hide behind payload due to len
{
if (svc & 0x20) fprintf (stderr, " Duplex");
if (svc & 0x10) fprintf (stderr, " Packet");
else fprintf (stderr, " Circuit");
if (svc & 0x8) fprintf (stderr, " R"); //reserved bit is on
fprintf (stderr, " Priority %d", svc & 0x7); //call priority
}
fprintf (stderr, " Unit to Unit Voice");
sprintf (state->call_string[slot], " Private ");
if (svc & 0x80) strcat (state->call_string[slot], " Emergency ");
else if (svc & 0x40) strcat (state->call_string[slot], " Encrypted ");
else strcat (state->call_string[slot], " ");
if (slot == 0)
{
@@ -1300,7 +1553,7 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
int lcolorcode = ((MAC[12+len_a] & 0xF) << 8) | MAC[13+len_a];
fprintf (stderr, "\n Network Status Broadcast - Extended \n");
fprintf (stderr, " LRA [%02X] WACN [%05X] SYSID [%03X] NAC [%03X] CHAN-T [%04X] CHAN-R [%04X]", lra, lwacn, lsysid, lcolorcode, channelt, channelr);
process_channel_to_freq (opts, state, channelt);
state->p25_cc_freq = process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
state->p25_cc_is_tdma = 1; //flag on for CC tuning purposes when system is qpsk
if (state->p2_hardset == 0 ) //state->p2_is_lcch == 1 shim until CRC is working, prevent bogus data
@@ -1316,17 +1569,21 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
if (MAC[1+len_a] == 0x7C)
{
int lra = MAC[2+len_a];
int cfva = MAC[3+len_a] >> 4;
int lsysid = ((MAC[3+len_a] & 0xF) << 8) | MAC[4+len_a];
int rfssid = MAC[5+len_a];
int siteid = MAC[6+len_a];
int channelt = (MAC[7+len_a] << 8) | MAC[8+len_a];
int sysclass = MAC[9+len_a];
if (1 == 1) //state->p2_is_lcch == 1
{
fprintf (stderr, "\n Adjacent Status Broadcast - Abbreviated\n");
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] SSC [%02X]", lra, rfssid, lsysid, siteid, channelt, sysclass);
process_channel_to_freq (opts, state, channelt);
}
fprintf (stderr, "\n Adjacent Status Broadcast - Abbreviated\n");
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] SSC [%02X]\n ", lra, rfssid, lsysid, siteid, channelt, sysclass);
if (cfva & 0x8) fprintf (stderr, " Conventional");
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
else fprintf (stderr, " Last Known");
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
process_channel_to_freq (opts, state, channelt);
}
@@ -1334,19 +1591,23 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
if (MAC[1+len_a] == 0xFC)
{
int lra = MAC[2+len_a];
int cfva = MAC[3+len_a] >> 4;
int lsysid = ((MAC[3+len_a] & 0xF) << 8) | MAC[4+len_a];
int rfssid = MAC[5+len_a];
int siteid = MAC[6+len_a];
int channelt = (MAC[7+len_a] << 8) | MAC[8+len_a];
int channelr = (MAC[9+len_a] << 8) | MAC[10+len_a];
int sysclass = MAC[9+len_a];
if (1 == 1) //state->p2_is_lcch == 1
{
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]", lra, rfssid, lsysid, siteid, channelt, channelr, sysclass);
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
}
int sysclass = MAC[11+len_a]; //need to re-check this
fprintf (stderr, "\n Adjacent Status Broadcast - Extended\n");
fprintf (stderr, " LRA [%02X] RFSS[%03d] SYSID [%03X] SITE [%03X] CHAN-T [%04X] CHAN-R [%04X] SSC [%02X]\n ", lra, rfssid, lsysid, siteid, channelt, channelr, sysclass);
if (cfva & 0x8) fprintf (stderr, " Conventional");
if (cfva & 0x4) fprintf (stderr, " Failure Condition");
if (cfva & 0x2) fprintf (stderr, " Up to Date (Correct)");
else fprintf (stderr, " Last Known");
if (cfva & 0x1) fprintf (stderr, " Valid RFSS Connection Active");
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
}

View File

@@ -13,6 +13,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//Figure out which PDU we are looking at, see above info on 8.4.1
//reorganize bits into bytes and process accordingly
//new slot variable with flipped assignment for SACCH
uint8_t slot = (state->currentslot ^ 1) & 1;
unsigned long long int SMAC[24] = {0}; //22.5 bytes for SACCH MAC PDUs
int byte = 0;
int k = 0;
@@ -117,6 +120,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
{
//reset fourv_counter and dropbyte on PTT
state->fourv_counter[0] = 0;
state->dropL = 256;
state->dmrburstL = 20;
fprintf (stderr, "\n VCH 0 - ");
@@ -139,6 +143,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
fprintf(stderr, " MPTT");
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
@@ -150,6 +155,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
{
//reset fourv_counter and dropbyte on PTT
state->fourv_counter[1] = 0;
state->dropR = 256;
state->payload_algidR = 0; //zero this out as well
state->dmrburstR = 20;
@@ -173,6 +179,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
fprintf(stderr, " MPTT");
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
@@ -191,6 +198,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
{
state->fourv_counter[0] = 0;
state->dropL = 256;
state->dmrburstL = 23;
state->payload_algid = 0;
state->payload_keyid = 0;
@@ -206,11 +214,15 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
//blank the call string here -- slot variable is already flipped accordingly for sacch
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (state->currentslot == 0)
{
state->fourv_counter[1] = 0;
state->dropR = 256;
state->dmrburstR = 23;
state->payload_algidR = 0;
state->payload_keyidR = 0;
@@ -236,12 +248,25 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 1, SMAC);
fprintf (stderr, "%s", KNRM);
//blank the call string here -- slot variable is already flipped accordingly for sacch
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (opcode == 0x4 && err == 0)
{
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
//if (state->currentslot == 1) state->dmrburstL = 21;
//else state->dmrburstR = 21;
#ifdef AERO_BUILD
if (opts->audio_out_type != 5)
{
if (state->currentslot == 1) state->dmrburstL = 21;
else state->dmrburstR = 21;
}
#else
if (state->currentslot == 1) state->dmrburstL = 21;
else state->dmrburstR = 21;
#endif
fprintf (stderr, " MAC_ACTIVE ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 1, SMAC);
@@ -251,13 +276,13 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
{
if (state->currentslot == 1)
{
state->dmrburstL = 21;
state->dmrburstL = 22;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
else
{
state->dmrburstR = 21;
state->dmrburstR = 22;
//close any open MBEout files
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
@@ -280,6 +305,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//Figure out which PDU we are looking at, see above info on 8.4.1
//reorganize bits into bytes and process accordingly
//new slot variable
uint8_t slot = state->currentslot;
unsigned long long int FMAC[24] = {0}; //19.5 bytes for FACCH MAC PDUs, add padding to end
int byte = 0;
int k = 0;
@@ -347,6 +375,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
{
//reset fourv_counter and dropbyte on PTT
state->fourv_counter[0] = 0;
state->dropL = 256;
state->dmrburstL = 20;
fprintf (stderr, "\n VCH 0 - ");
@@ -369,6 +398,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algid);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyid);
fprintf (stderr, " MI 0x%016llX", state->payload_miP);
if (state->R != 0 && state->payload_algid == 0xAA) fprintf (stderr, " Key 0x%010llX", state->R);
fprintf(stderr, " MPTT");
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
@@ -380,6 +410,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
{
//reset fourv_counter and dropbyte on PTT
state->fourv_counter[1] = 0;
state->dropR = 256;
state->dmrburstR = 20;
fprintf (stderr, "\n VCH 1 - ");
@@ -402,6 +433,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
fprintf (stderr, "\n ALG ID 0x%02X", state->payload_algidR);
fprintf (stderr, " KEY ID 0x%04X", state->payload_keyidR);
fprintf (stderr, " MI 0x%016llX", state->payload_miN);
if (state->RR != 0 && state->payload_algidR == 0xAA) fprintf (stderr, " Key 0x%010llX", state->RR);
fprintf(stderr, " MPTT");
// fprintf (stderr, " %s", KRED);
// fprintf (stderr, "ENC");
@@ -419,6 +451,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
{
state->fourv_counter[0] = 0;
state->dropL = 256;
state->dmrburstL = 23;
state->payload_algid = 0; //zero this out as well
state->payload_keyid = 0;
@@ -433,12 +466,16 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
//blank the call string here
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (state->currentslot == 1)
{
state->fourv_counter[1] = 0;
state->dropR = 256;
state->dmrburstR = 23;
state->payload_algidR = 0; //zero this out as well
state->payload_keyidR = 0;
@@ -484,12 +521,25 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 0, FMAC);
fprintf (stderr, "%s", KNRM);
//blank the call string here
sprintf (state->call_string[slot], "%s", " "); //21 spaces
}
if (opcode == 0x4 && err == 0)
{
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
//if (state->currentslot == 0) state->dmrburstL = 21;
//else state->dmrburstR = 21;
#ifdef AERO_BUILD
if (opts->audio_out_type != 5)
{
if (state->currentslot == 0) state->dmrburstL = 21;
else state->dmrburstR = 21;
}
#else
if (state->currentslot == 0) state->dmrburstL = 21;
else state->dmrburstR = 21;
#endif
fprintf (stderr, " MAC_ACTIVE ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 0, FMAC);

View File

@@ -1,584 +1,432 @@
#include "dsd.h"
#include "provoice_const.h"
void
processProVoice (dsd_opts * opts, dsd_state * state)
// #define PVDEBUG
void processProVoice (dsd_opts * opts, dsd_state * state)
{
int i, j, dibit, k;
uint8_t lid[80];
uint8_t lidbyte[10];
uint8_t init[64];
uint8_t initbyte[8];
int i, j, dibit;
char imbe7100_fr1[7][24];
char imbe7100_fr2[7][24];
const int *w, *x;
//raw bits storage for analysis
uint8_t raw_bits[800];
memset (raw_bits, 0, sizeof(raw_bits));
//raw bytes storage for analysis
uint8_t raw_bytes[100];
memset (raw_bytes, 0, sizeof(raw_bytes));
unsigned long long int initial = 0; //initial 64-bits before the lid
uint16_t lid = 0; //lid value 16-bit
unsigned long long int secondary = 0; //secondary 64-bits after lid, before voice
uint8_t spacer_bit[8]; //check this value to see if its a status thing (like P25 P1)
memset (spacer_bit, 0, sizeof (spacer_bit));
uint8_t spacer = 0;
uint16_t bf = 0; //the 16-bit value in-between imbe 2 and imbe 3 that is usually 2175
fprintf (stderr," VOICE");
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1)
//print group and source values if EA trunked
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->ea_mode == 1)
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Site [%02llX][%03lld] Group [%05d] Source [%08d] LCN[%02d] ",
state->edacs_site_id, state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
fprintf (stderr, " Site: %lld Group: %d Source: %d LCN: %d ",
state->edacs_site_id, state->lasttg, state->lastsrc, state->edacs_tuned_lcn);
fprintf (stderr, "%s", KNRM);
}
//print afs value if standard/networked trunked
else if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && state->ea_mode == 0)
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Site: %lld AFS: %d-%d LCN: %d ",
state->edacs_site_id, (state->lastsrc >> 7) & 0xF, state->lastsrc & 0x7F, state->edacs_tuned_lcn);
fprintf (stderr, "%s", KNRM);
}
for (i = 0; i < 64; i++)
{
dibit = getDibit (opts, state);
init[i] = dibit;
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
//iNitial 64 bits
//load all initial bits before voice into raw_bits array for analysis/handling
for (i = 0; i < 64+16+64; i++)
raw_bits[i] = getDibit (opts, state);
//Note: the initial 144-bits seem to be provisioned differently depending on system type
initial = (unsigned long long int)ConvertBitIntoBytes(&raw_bits[0], 64);
lid = (uint16_t)ConvertBitIntoBytes(&raw_bits[64], 16);
secondary = (unsigned long long int)ConvertBitIntoBytes(&raw_bits[80], 64);
if (opts->payload == 1)
{
k = 0;
fprintf (stderr, "\n N64: ");
for(i = 0; i < 8; i++)
{
initbyte[i] = 0;
for (j = 0; j < 8; j++)
{
initbyte[i] = initbyte[i] << 1;
initbyte[i] = initbyte[i] | init[k];
k++;
}
fprintf (stderr, "%02X", initbyte[i]);
if (i == 3) fprintf (stderr, "-");
}
fprintf (stderr, "\n");
fprintf (stderr, "\n N64: %016llX", initial);
fprintf (stderr, "\n LID: %04X", lid);
fprintf (stderr, " %016llX", secondary);
}
// lid
for (i = 0; i < 16; i++)
{
dibit = getDibit (opts, state);
lid[i] = dibit;
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
for (i = 0; i < 64; i++)
{
dibit = getDibit (opts, state);
lid[i+16] = dibit;
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
//load lid (bits) into lidbyte
if (opts->payload == 1)
{
k = 0;
fprintf (stderr, " LID: ");
for(i = 0; i < 10; i++)
{
lidbyte[i] = 0;
for (j = 0; j < 8; j++)
{
lidbyte[i] = lidbyte[i] << 1;
lidbyte[i] = lidbyte[i] | lid[k];
k++;
}
fprintf (stderr, "%02X", lidbyte[i]);
if (i == 3 || i == 7) fprintf (stderr, "-");
}
// fprintf (stderr, "\n");
}
// imbe frames 1,2 first half
w = pW;
x = pX;
for (i = 0; i < 11; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
}
for (j = 0; j < 6; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[144+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[150+j+(i*12)] = dibit;
}
}
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+282] = dibit;
}
w -= 6;
x -= 6;
for (j = 0; j < 4; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+288] = dibit;
}
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
spacer_bit[0] = dibit;
raw_bits[292] = dibit;
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
fprintf (stderr," ");
#endif
spacer_bit[1] = dibit;
raw_bits[293] = dibit;
// imbe frames 1,2 second half
for (j = 0; j < 2; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+294] = dibit;
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
}
for (j = 0; j < 5; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[296+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[302+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+338] = dibit;
}
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+343] = dibit;
}
for (i = 0; i < 7; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
}
for (j = 0; j < 5; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[348+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[354+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+438] = dibit;
}
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+443] = dibit;
}
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
spacer_bit[2] = dibit;
raw_bits[448] = dibit;
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
fprintf (stderr," ");
#endif
spacer_bit[3] = dibit;
raw_bits[449] = dibit;
//resume raw_bits at +6 current value to round out payload bytes
//easier to visualize patterns
for (i = 0; i < 16; i++)
{
dibit = getDibit (opts, state); //HERE
init[i] = dibit; //recycle
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
if (opts->payload == 1)
{
k = 0;
fprintf (stderr, "\n 16B: ");
for(i = 0; i < 2; i++)
{
initbyte[i] = 0;
for (j = 0; j < 8; j++)
{
initbyte[i] = initbyte[i] << 1;
initbyte[i] = initbyte[i] | init[k];
k++;
}
fprintf (stderr, "%02X", initbyte[i]);
}
// fprintf (stderr, "\n");
}
raw_bits[i+450+6] = getDibit (opts, state);
bf = (uint16_t)ConvertBitIntoBytes(&raw_bits[456], 16);
if (opts->payload == 1)
fprintf (stderr, "\n BF: %04X ", bf);
// imbe frames 3,4 first half
w = pW;
x = pX;
for (i = 0; i < 11; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
}
for (j = 0; j < 6; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[6+466+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[6+472+j+(i*12)] = dibit;
}
}
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+604+6] = dibit;
}
w -= 6;
x -= 6;
for (j = 0; j < 4; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[i+610+6] = dibit;
}
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
spacer_bit[4];
raw_bits[614+2] = dibit;
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
//fprintf (stderr,"_");
#endif
spacer_bit[5];
raw_bits[615+2] = dibit;
// imbe frames 3,4 second half
for (j = 0; j < 2; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+616+6] = dibit;
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
}
for (j = 0; j < 5; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[6+618+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[6+624+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr," ");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+660+6] = dibit;
}
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+665+6] = dibit;
}
for (i = 0; i < 7; i++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
}
for (j = 0; j < 5; j++)
{
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[6+670+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr,"_");
#endif
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
w -= 6;
x -= 6;
for (j = 0; j < 6; j++)
{
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[6+676+j+(i*12)] = dibit;
}
#ifdef PROVOICE_DUMP
//fprintf (stderr," ");
#endif
}
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr1[*w][*x] = dibit;
w++;
x++;
raw_bits[j+760+6] = dibit;
}
w -= 5;
x -= 5;
for (j = 0; j < 5; j++)
{
dibit = getDibit (opts, state);
imbe7100_fr2[*w][*x] = dibit;
w++;
x++;
raw_bits[j+765+6] = dibit;
}
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
// spacer bits
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
#endif
spacer_bit[6] = dibit;
raw_bits[782] = dibit;
dibit = getDibit (opts, state);
#ifdef PROVOICE_DUMP
//fprintf (stderr,"%i", dibit);
//fprintf (stderr," ");
spacer_bit[7] = dibit;
raw_bits[783] = dibit;
#ifdef PVDEBUG
spacer = (uint8_t)ConvertBitIntoBytes(&spacer_bit[0], 8);
if (opts->payload == 1)
fprintf (stderr, "\n SP: %X", spacer);
//convert raw bits into raw bytes for payload analysis
for (j = 0; j < 98; j++)
{
raw_bytes[j] = (uint8_t)ConvertBitIntoBytes(&raw_bits[(j*8)], 8);
}
//payload on all raw bytes for analysis...its a lot of 'em
if (opts->payload == 1) //find better thingy later or change this
// if (opcode != 0x3333)
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, "\n pV Payload Dump: \n ");
for (j = 0; j < 98; j++)
{
fprintf (stderr, "[%02X]", raw_bytes[j]);
if (j == 17 || j == 35 || j == 53 || j == 71 || j == 89)
{
fprintf (stderr, "\n ");
}
}
fprintf (stderr, "%s", KNRM);
}
#endif
if (opts->errorbars == 1)
{
fprintf (stderr,"\n");
}
//line break at end of frame
fprintf (stderr,"\n");
}

View File

@@ -31,12 +31,12 @@
#include <rtl-sdr.h>
#include "dsd.h"
//#define DEFAULT_SAMPLE_RATE 48000 //moved to opts->rtl_bandwidth
#define DEFAULT_SAMPLE_RATE 48000
#define DEFAULT_BUF_LENGTH (1 * 16384)
#define MAXIMUM_OVERSAMPLE 16 //16
#define MAXIMUM_OVERSAMPLE 16
#define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH)
#define AUTO_GAIN -100
#define BUFFER_DUMP 4096
#define BUFFER_DUMP 4096
#define FREQUENCIES_LIMIT 1000
@@ -46,7 +46,8 @@ static int ACTUAL_BUF_LENGTH;
static int *atan_lut = NULL;
static int atan_lut_size = 131072; /* 512 KB */
static int atan_lut_coef = 8;
//new for UDP
//UDP -- keep for compatibility reasons
#include <netinet/in.h>
#include <arpa/inet.h>
static pthread_t socket_freq;
@@ -57,7 +58,7 @@ int bandwidth_divisor = 48000; //divide bandwidth by this to get multiplier for
short int volume_multiplier;
short int port;
//
struct dongle_state
{
int exit_flag;
@@ -462,11 +463,14 @@ void dc_block_filter(struct demod_state *fm)
}
fm->dc_avg = avg;
}
int rms(int16_t *samples, int len, int step)
//TODO: Fix This so we don't get random negative values in Cygwin (or 32-bit builds?)
//Fixed -- I honestly think the issue is Cygwin can't keep up and if it can't run enough samples in the other thread,
//then it reports some jank values, really unsure, I've never seen the issue in Linux side though
long int rms(int16_t *samples, int len, int step)
/* largely lifted from rtl_power */
{
int i;
long int rms;
long p, t, s;
double dc, err;
@@ -480,7 +484,10 @@ int rms(int16_t *samples, int len, int step)
dc = (double)(t*step) / (double)len;
err = t * 2 * dc - dc * dc * len;
return (int)sqrt((p-err) / len);
rms = (long int)sqrt((p-err) / len);
//going with a value that's easy to figure out when its done the thing
if (rms < 0){ rms = 999; } //need to text nxdn with this setup to make sure it isn't broken in Windows Cygwin now
return rms;
}
void full_demod(struct demod_state *d)
@@ -597,7 +604,6 @@ static void *demod_thread_fn(void *arg)
int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
{
//target_gain = 36;
int i, r, err1, err2, count, nearest;
int* gains;
r = rtlsdr_set_tuner_gain_mode(dev, 1);
@@ -628,10 +634,9 @@ int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
int r;
r = rtlsdr_set_center_freq(dev, frequency);
if (r < 0) {
fprintf (stderr, "WARNING: Failed to set center freq.\n");
fprintf (stderr, " (WARNING: Failed to set Center Frequency). \n");
} else {
//fprintf (stderr, "Tuned to %u Hz.\n", frequency);
fprintf (stderr, "Tuned to center frequency %u Hz.\n", frequency);
fprintf (stderr, " (Center Frequency: %u Hz.) \n", frequency);
}
return r;
}
@@ -679,7 +684,6 @@ int verbose_offset_tuning(rtlsdr_dev_t *dev)
int verbose_auto_gain(rtlsdr_dev_t *dev)
{
int r;
r = rtlsdr_set_tuner_gain_mode(dev, 0);
if (r != 0) {
@@ -692,7 +696,6 @@ int verbose_auto_gain(rtlsdr_dev_t *dev)
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
{
//gain = 36;
int r;
r = rtlsdr_set_tuner_gain_mode(dev, 1);
if (r < 0) {
@@ -710,7 +713,6 @@ int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
{
//ppm_error = -2; //fix this opt arg to accept negative float values, i.e. float or double??
int r;
if (ppm_error == 0) {
return 0;}
@@ -732,25 +734,23 @@ int verbose_reset_buffer(rtlsdr_dev_t *dev)
return r;
}
//static void optimal_settings(struct fm_state *fm, int freq, int hopping)
static void optimal_settings(int freq, int rate) //
static void optimal_settings(int freq, int rate)
{
// giant ball of hacks
// seems unable to do a single pass, 2:1
//int r, capture_freq, capture_rate;
int capture_freq, capture_rate;
struct dongle_state *d = &dongle;
struct demod_state *dm = &demod;
struct controller_state *cs = &controller;
dm->downsample = (1000000 / dm->rate_in) + 1;
dm->downsample = (1000000 / dm->rate_in) + 1; //dm->rate_in is the rtl_bandwidth value
if (dm->downsample_passes) {
dm->downsample_passes = (int)log2(dm->downsample) + 1;
dm->downsample = 1 << dm->downsample_passes;
}
capture_freq = freq;
capture_rate = dm->downsample * dm->rate_in;
capture_rate = dm->downsample * dm->rate_in; //
if (!d->offset_tuning) {
capture_freq = freq + capture_rate/4;}
capture_freq = freq + capture_rate/4;} //
capture_freq += cs->edge * dm->rate_in / 2;
dm->output_scale = (1<<15) / (128 * dm->downsample);
if (dm->output_scale < 1) {
@@ -759,6 +759,7 @@ static void optimal_settings(int freq, int rate) //
dm->output_scale = 1;}
d->freq = (uint32_t)capture_freq;
d->rate = (uint32_t)capture_rate;
// fprintf (stderr, "Capture Frequency: %i Rate: %i \n", capture_freq, capture_rate);
}
static void *controller_thread_fn(void *arg)
@@ -790,7 +791,6 @@ static void *controller_thread_fn(void *arg)
/* Set the sample rate */
verbose_set_sample_rate(dongle.dev, dongle.rate);
fprintf (stderr, "Output at %u Hz.\n", demod.rate_in/demod.post_downsample);
fprintf (stderr, "Press CTRL + C to close.\n");
while (!exitflag) {
safe_cond_wait(&s->hop, &s->hop_m);
@@ -807,20 +807,16 @@ static void *controller_thread_fn(void *arg)
void dongle_init(struct dongle_state *s)
{
//s->rate = DEFAULT_SAMPLE_RATE;
s->rate = rtl_bandwidth;
s->gain = AUTO_GAIN; // tenths of a dB
s->mute = 0;
s->direct_sampling = 0;
s->offset_tuning = 0; //
s->offset_tuning = 0; //E4000 tuners only
s->demod_target = &demod;
}
void demod_init(struct demod_state *s)
{
//s->rate_in = DEFAULT_SAMPLE_RATE;
//s->rate_out = DEFAULT_SAMPLE_RATE;
s->rate_in = rtl_bandwidth;
s->rate_out = rtl_bandwidth;
s->squelch_level = 0;
@@ -830,16 +826,16 @@ void demod_init(struct demod_state *s)
s->downsample_passes = 0;
s->comp_fir_size = 0;
s->prev_index = 0;
s->post_downsample = 1; // once this works, default = 4
s->post_downsample = 1; //1 -- once this works, default = 4 -- doesn't work on the official rtl-sdr source code either
s->custom_atan = 0;
s->deemph = 0;
s->rate_out2 = -1; // flag for disabled
s->rate_out2 = rtl_bandwidth; // -1 flag for disabled -- this enables low_pass_real, seems to work okay
s->mode_demod = &fm_demod;
s->pre_j = s->pre_r = s->now_r = s->now_j = 0;
s->prev_lpr_index = 0;
s->deemph_a = 0;
s->now_lpr = 0;
s->dc_block = 0;
s->dc_block = 1; //enabling by default, but offset tuning is also enabled, so center spike shouldn't be an issue
s->dc_avg = 0;
pthread_rwlock_init(&s->rw, NULL);
pthread_cond_init(&s->ready, NULL);
@@ -856,7 +852,6 @@ void demod_cleanup(struct demod_state *s)
void output_init(struct output_state *s)
{
//s->rate = DEFAULT_SAMPLE_RATE;
s->rate = rtl_bandwidth;
pthread_rwlock_init(&s->rw, NULL);
pthread_cond_init(&s->ready, NULL);
@@ -904,7 +899,8 @@ void sanity_checks(void)
}
}
//UDP remote all below HERE
//UDP remote stuff
static unsigned int chars_to_int(unsigned char* buf) {
int i;
@@ -918,9 +914,7 @@ static unsigned int chars_to_int(unsigned char* buf) {
}
static void *socket_thread_fn(void *arg) {
//struct fm_state *fm = arg;
struct demod_state *d = static_cast<demod_state*>(arg);
//int port = 6020;
int r, n;
int sockfd, newsockfd, portno;
socklen_t clilen;
@@ -952,114 +946,34 @@ static void *socket_thread_fn(void *arg) {
while((n = read(sockfd,buffer,5)) != 0) {
if(buffer[0] == 0) {
new_freq = chars_to_int(buffer);
dongle.freq = new_freq; //
//opts->rtlsdr_center_freq = new_freq; //or dongle.freq, this should update the freq displayed in ncurses terminal hopefully and not do anything naughty
dongle.freq = new_freq;
optimal_settings(new_freq, demod.rate_in);
rtlsdr_set_center_freq(dongle.dev, dongle.freq);
//verbose_set_frequency (dongle.dev, new_freq);
//fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset);
fprintf (stderr, "\nTuning to: %d [Hz] \n", new_freq);
}
/*
if(buffer[0] == 1) {
// change demod type
int type = chars_to_int(buffer);
switch(type) {
case 0:
fprintf (stderr, "Changing demod type to FM\n");
fm->mode_demod = &fm_demod;
break;
case 1:
fprintf (stderr, "Changing demod type to AM\n");
fm->mode_demod = &am_demod;
break;
case 2:
fprintf (stderr, "Changing demod type to USB\n");
fm->mode_demod = &usb_demod;
fm->custom_atan = 1;
break;
case 3:
fprintf (stderr, "Changing demod type to LSB\n");
fm->mode_demod = &lsb_demod;
break;
default:
fprintf (stderr, "Unknown demod type %d\n", type);
break;
}
}
*/
//SQUELCH HERE
if (buffer[0] == 2) {
new_squelch = chars_to_int(buffer);
demod.squelch_level = new_squelch; //demod, or d*? or d->
//full_demod(d);
//new_freq = 850000000;
//dongle.freq = new_freq;
//optimal_settings(new_freq, demod.rate_in); //hacky way to 'squelch', just setting it to a dead freq instead
//rtlsdr_set_center_freq(dongle.dev, dongle.freq);
fprintf (stderr, "Changing squelch to %d \n", new_squelch);
}
/*
if (buffer[0] == 3) {
new_gain = chars_to_int(buffer);
if (new_gain == AUTO_GAIN) {
r = rtlsdr_set_tuner_gain_mode(dev, 0);
} else {
r = rtlsdr_set_tuner_gain_mode(dev, 1);
new_gain = nearest_gain(new_gain);
r = rtlsdr_set_tuner_gain(dev, new_gain);
}
if (r != 0) {
fprintf (stderr, "WARNING: Failed to set tuner gain.\n");
} else if (new_gain == AUTO_GAIN) {
fprintf (stderr, "Tuner gain set to automatic.\n");
} else {
fprintf (stderr, "Tuner gain set to %0.2f dB.\n", new_gain/10.0);
}
}
*/
/*
if (buffer[0] == 8) {
agc_mode = chars_to_int(buffer);
if (agc_mode == 0 || agc_mode == 1) {
fprintf (stderr, "Setting AGC to %d\n", agc_mode);
rtlsdr_set_agc_mode(dev, agc_mode);
} else {
fprintf (stderr, "Failed to set AGC to %d\n", agc_mode);
}
}
*/
}
close(sockfd);
return 0;
}
//UDP Control all above HERE
//UDP stuff end
void rtlsdr_sighandler()
{
//fprintf (stderr, "Signal caught, exiting!\n");
//fprintf (stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C
fprintf (stderr, "Signal caught, exiting!\n");
rtlsdr_cancel_async(dongle.dev);
//cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work
//_Exit(1);
}
void open_rtlsdr_stream(dsd_opts *opts)
{
struct sigaction sigact;
int r;
rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
//rtl_bandwidth = 48000;
rtl_bandwidth = opts->rtl_bandwidth * 1000; //reverted back to straight value
bandwidth_multiplier = (bandwidth_divisor / rtl_bandwidth);
//bandwidth_multiplier = 1;
//this needs to be initted first, then we set the parameters
dongle_init(&dongle);
demod_init(&demod);
output_init(&output);
@@ -1070,29 +984,23 @@ void open_rtlsdr_stream(dsd_opts *opts)
controller.freq_len++;
}
if (opts->rtlsdr_ppm_error > 0 || opts->rtlsdr_ppm_error < 0) { //this way will adjust PPM based on negative values as well
if (opts->rtlsdr_ppm_error != 0) {
dongle.ppm_error = opts->rtlsdr_ppm_error;
fprintf (stderr, "Setting RTL PPM Error Set to %d\n", opts->rtlsdr_ppm_error);
}
if (opts->audio_in_type == 3) {
dongle.dev_index = opts->rtl_dev_index;
//rtl_bandwidth = opts->rtl_bandwidth * 1000; //multiple by 1000 to get rate
//rtl_bandwidth = 48000;
//bandwidth_multiplier = rtl_bandwidth / bandwidth_divisor; //find multiple with no remainder if oddball number entered
//bandwidth_multiplier = 1;
demod.squelch_level = opts->rtl_squelch_level; //adding user definable squelch level to prevent false positives on account of noise in NXDN etc
fprintf (stderr, "Setting RTL VFO Bandwidth to %d Hz\n", rtl_bandwidth);
fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
fprintf (stderr, "Setting RTL Squelch Level to %d\n", demod.squelch_level);
port = opts->rtl_udp_port;
}
dongle.dev_index = opts->rtl_dev_index;
// demod.squelch_level = opts->rtl_squelch_level; //no longer used here, used in framesync vc rms value under select conditions
fprintf (stderr, "Setting RTL Bandwidth to %d Hz\n", rtl_bandwidth);
// fprintf (stderr, "Setting RTL Sample Multiplier to %d\n", bandwidth_multiplier);
fprintf (stderr, "Setting RTL RMS Squelch Level to %d\n", opts->rtl_squelch_level);
if (opts->rtl_udp_port != 0) port = opts->rtl_udp_port; //set this here, only open socket thread if set
if (opts->rtl_gain_value > 0) {
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm really works
dongle.gain = opts->rtl_gain_value * 10; //multiple by ten to make it consitent with the way rtl_fm works
}
volume_multiplier = opts->rtl_volume_multiplier;
fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
// fprintf (stderr, "Setting RTL Volume Multiplier to %d\n", volume_multiplier);
/* quadruple sample_rate to limit to Δθ to ±π/2 */
demod.rate_in *= demod.post_downsample;
@@ -1103,24 +1011,16 @@ void open_rtlsdr_stream(dsd_opts *opts)
if (controller.freq_len > 1) demod.terminate_on_squelch = 0;
ACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);
if (r < 0)
{
fprintf (stderr, "Failed to open rtlsdr device %d.\n", dongle.dev_index);
exit(1);
} else {
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index); //Kindly tell us which device we are using
fprintf (stderr, "Using RTLSDR Device Index: %d. \n", dongle.dev_index);
}
// sigact.sa_handler = sighandler;
// sigemptyset(&sigact.sa_mask);
// sigact.sa_flags = 0;
// sigaction(SIGINT, &sigact, NULL);
// sigaction(SIGTERM, &sigact, NULL);
// sigaction(SIGQUIT, &sigact, NULL);
// sigaction(SIGPIPE, &sigact, NULL);
if (demod.deemph) {
demod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * 75e-6)))));
}
@@ -1128,9 +1028,11 @@ void open_rtlsdr_stream(dsd_opts *opts)
/* Set the tuner gain */
if (dongle.gain == AUTO_GAIN) {
verbose_auto_gain(dongle.dev);
fprintf (stderr, "Setting RTL Autogain. \n");
} else {
dongle.gain = nearest_gain(dongle.dev, dongle.gain);
verbose_gain_set(dongle.dev, dongle.gain);
// fprintf (stderr, "Setting RTL Nearest Gain to %d. \n", dongle.gain); //seems to be working now
}
verbose_ppm_set(dongle.dev, dongle.ppm_error);
@@ -1142,7 +1044,8 @@ void open_rtlsdr_stream(dsd_opts *opts)
usleep(100000);
pthread_create(&demod.thread, NULL, demod_thread_fn, (void*)(&demod));
pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void*)(&dongle));
pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
//only create socket thread IF user specified (for legacy uses), else don't use it
if (port != 0) pthread_create(&socket_freq, NULL, socket_thread_fn, (void *)(&controller));
}
void cleanup_rtlsdr_stream()
@@ -1155,8 +1058,6 @@ void cleanup_rtlsdr_stream()
safe_cond_signal(&output.ready, &output.ready_m);
safe_cond_signal(&controller.hop, &controller.hop_m);
pthread_join(controller.thread, NULL);
//add socket thread
//pthread_join(socket_freq, NULL);
//dongle_cleanup(&dongle);
demod_cleanup(&demod);
@@ -1164,32 +1065,70 @@ void cleanup_rtlsdr_stream()
controller_cleanup(&controller);
rtlsdr_close(dongle.dev);
}
//void get_rtlsdr_sample(int16_t *sample)
//original for safe keeping
// void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
// {
// if (output.queue.empty())
// {
// safe_cond_wait(&output.ready, &output.ready_m);
// }
// pthread_rwlock_wrlock(&output.rw);
// *sample = output.queue.front() * volume_multiplier;
// output.queue.pop();
// pthread_rwlock_unlock(&output.rw);
// }
//find way to modify this function to allow hopping (tuning) while squelched and send 0 sample?
void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state)
{
if (output.queue.empty())
{
if (opts->use_ncurses_terminal == 1)
{
//ncursesPrinter(opts, state);
//printw ("\n\n\n HELP I'M LOCKED!\n");
}
safe_cond_wait(&output.ready, &output.ready_m);
//goto END;
}
pthread_rwlock_wrlock(&output.rw);
//*sample = output.queue.front();
*sample = output.queue.front() * volume_multiplier; //try multiplying by numbers here for 'gain'
*sample = output.queue.front() * volume_multiplier;
output.queue.pop();
pthread_rwlock_unlock(&output.rw);
// END:
// if (1 == 2)
// {
// fprintf (stderr, "This is a dumb thing to fix");
// }
}
//function may lag since it isn't running as its own thread
void rtl_dev_tune(dsd_opts * opts, long int frequency)
{
int r;
if (opts->payload == 1)
fprintf (stderr, "\nTuning to %lu Hz.", frequency);
dongle.freq = opts->rtlsdr_center_freq = frequency;
optimal_settings(dongle.freq, demod.rate_in);
if (opts->payload == 1)
fprintf (stderr, " (Center Frequency: %u Hz.) \n", dongle.freq);
r = rtlsdr_set_center_freq(dongle.dev, dongle.freq);
if (r < 0)
fprintf (stderr, " (WARNING: Failed to set Center Frequency %u). \n", dongle.freq);
pthread_rwlock_wrlock(&output.rw); //prevent possible segfault when cleaning the queue
rtl_clean_queue();
pthread_rwlock_unlock(&output.rw); //resume
}
//return RMS value (root means square) power level -- used as soft squelch inside of framesync
long int rtl_return_rms()
{
long int sr = 0;
#ifdef __arm__
sr = 100;
#else
sr = rms(demod.lowpassed, demod.lp_len, 1);
#endif
return (sr);
}
//simple function to clear the rtl sample queue when tuning and during other events (ncurses menu open/close)
void rtl_clean_queue()
{
//insert method to clear the entire queue to prevent sample 'lag'
std::queue<int16_t> empty; //create an empty queue
std::swap( output.queue, empty ); //swap in empty queue to effectively zero out current queue
}

View File

@@ -1,539 +0,0 @@
/*
* Copyright (C) 2016 by Jonathan Naylor, G4KLX
*
* Heavy Modificatins of Original Code to work for DSD-FME
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "dsd.h"
#include <cstdio>
#include <cassert>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U,
2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U,
4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U,
6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U};
const unsigned char ENCODE_TABLE[] = {
0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U,
4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U,
1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U,
5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U,
3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U,
7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U,
2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U,
6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U};
const unsigned char DECODE_TABLE[] = { //flip the rows and columns, right?
0,4,1,5,3,7,2,6,
8,12,9,13,11,15,10,14,
4,2,5,3,7,1,6,0,
12,10,13,11,15,9,14,8,
2,6,3,7,1,5,0,4,
10,14,11,15,9,13,8,12,
6,0,7,1,5,3,4,2,
14,8,15,9,13,11,12,10
};
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
unsigned char state = 0U;
//rework quickHamming to accept unsigned intergers instead and go bit by bit
int quickHamming(unsigned int butt, unsigned int farts)
{
unsigned int i = 0, count = 0, shit = 0, shart = 0;
//fprintf (stderr, "Distance Compare %X - %X \n", butt, farts );
for (i; i < 3; i++) //shift three places tops;
{
shit = (butt >> i) & 0b1;
shart = (farts >> i) & 0b1;
if (shit != shart)
{
count++;
}
}
return count;
}
bool CDMRTrellisFixCode(unsigned char* points, unsigned int failPos, unsigned char* payload)
{
//unsigned int bestPos = 0U;
//unsigned int bestVal = 0U;
for (unsigned j = 0U; j < 20U; j++) {
unsigned int bestPos = 0U;
unsigned int bestVal = 0U;
//fprintf (stderr, " fail%d-", failPos);
for (unsigned int i = 0U; i < 16U; i++) {
points[failPos] = i;
//fprintf (stderr, "i%d", i);
unsigned char tribits[49U];
unsigned int pos = CDMRTrellisCheckCode(points, tribits);
if (pos == 999U) {
CDMRTrellisTribitsToBits(tribits, payload);
return true;
}
if (pos > bestPos) {
bestPos = pos;
bestVal = i;
}
}
points[failPos] = bestVal;
failPos = bestPos;
}
return false;
}
void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* payload)
{
unsigned char bits[144];
for (int i = 0; i < 48; i++) {
bits[(i * 3) + 0] = (tribits[i] >> 2) & 1;
bits[(i * 3) + 1] = (tribits[i] >> 1) & 1;
bits[(i * 3) + 2] = tribits[i] & 1;
}
// convert bits to bytes
//fprintf (stderr, "\n Tribit Binary Sequence\n ");
for (short i = 0; i < 144; i++)
{
//fprintf (stderr, "%b", bits[i]);
}
for(short int i = 0; i < 18; i++)
{
payload[i] = (bits[i * 8 + 0] << 7) | (bits[i * 8 + 1] << 6) | (bits[i * 8 + 2] << 5) | (bits[i * 8 + 3] << 4) |
(bits[i * 8 + 4] << 3) | (bits[i * 8 + 5] << 2) | (bits[i * 8 + 6] << 1) | (bits[i * 8 + 7] << 0);
}
//for (int i = 0; i < 144; i++)
//payload[i/8] = (payload[i/8] << 1) | bits[i];
//DmrDataBit[j + 0] = (TrellisReturn[17-i] >> 0) & 0x01; //example
}
unsigned int CDMRTrellisCheckCode(const unsigned char* points, unsigned char* tribits)
{
//unsigned char state = 0U; //move outside of function to preserve state for every iteration
//let's try reversing the points to pass through the decode table instead of flipping them here,
//it may mess up the fixcode and failpos POS
state = 0U;
for (unsigned int i = 0U; i < 49U;) //total number of points to process
{
tribits[i] = 9U;
for (unsigned int j = 0U; j < 8U; j++)
{
//if (points[i] == DECODE_TABLE[state * 8U + j])
//if (points[48-i] == DECODE_TABLE[state * 8U + j])
if (points[i] == ENCODE_TABLE[state * 8U + j])
{
tribits[i] = j;
state = tribits[i]; //carry over if found right away
i++; //increment i by one value
break;
}
}
//try to find shortest distance for surviving paths and decide on one
//seems to be that two paths will have distance value 1, and two will have distance value 2
//need to keep totaling up a few rounds before we can eliminate a path and resume?
if (tribits[i] == 9U)
{
int distance = 0;
int maxdistance = 99; //random metric for two position distance
int pathdistance = 0;
unsigned int match = 0;
unsigned int nextmatch = 0;
unsigned int q = 0;
//only 4 possible states for each point, but in 8 (0-7) FSM states
char path[99][99] = {0}; //[i][pathcount] = distance
int pathcount = 0;
for (unsigned int o = 0; o < 64; o++) //check entire state transition table for matches
{
if (points[i] == ENCODE_TABLE[o]) //ENCODE TABLE
{
match = o / (unsigned int)8; //get dividend no remainder/decimal I hope, get fsm state 0-7
//fprintf (stderr, "\n Point #%d [%d] Match State %d Position %d Tribit Value %d \n", i, points[i], match, o, o % (unsigned int)8);
distance = quickHamming(match, state);
//fprintf (stderr, "Raw Distance Current %d\n", distance);
path[i][pathcount] = distance ; //save which table values (paths) match as possible values and distance
for (q; q < 64; q++) //check entire state transition table for next point match
{
if (points[i+1] == ENCODE_TABLE[q]) //ENCODE TABLE
{
nextmatch = q / (unsigned int)8;
path[i+1][pathcount] = quickHamming(nextmatch, q % (unsigned int)8);
//fprintf (stderr, "Raw Distance Next %d\n", path[i+1][pathcount]);
pathcount++;
//fprintf (stderr, "State 0 Match %d Distance %d \n", o, distance);
}
}
for (short int z = 0; z <= pathcount; z++) //add metrics on paths to find shortest distance
{
pathdistance = path[i][0] + path[i+1][z];
//fprintf (stderr, "Total Path Distance %d\n", pathdistance);
if (pathdistance <= maxdistance) //equal too in case of tie?
{
maxdistance = pathdistance;
tribits[i] = o % (unsigned int)8; //remainder value will be tribit value on table
if (i < 49) //just in case we are on 49 already, don't want to crash or something.
{
tribits[i+1] = q % (unsigned int)8; //remainder value will be tribit value on table
}
//fprintf (stderr, "Point #%d [%d] - Tribit Candidate %d\n", i, points[i], tribits[i] );
//fprintf (stderr, "Point #%d [%d]- Tribit Candidate %d\n", i+1, points[i+1], tribits[i+1] );
}
}
}
//fprintf (stderr, "Selected Point #%d [%d] - Tribit Selection %d\n", i, points[i], tribits[i] );
//fprintf (stderr, "Selected Point #%d [%d]- Tribit Selection %d\n", i+1, points[i+1], tribits[i+1] );
}
state = tribits[i+1]; //not quite sure if this will be needed or not, if so, set state to last found value
i += 2; //increment i by two since we already got the next tribit value as well;
//state = tribits[i]; //not quite sure if this will be needed or not, if so, set state to last found value
//i++; //increment i by two since we already got the next tribit value as well;
}
}
return 999U;
}
void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits)
{
int n;
signed char dibit;
//can only assume this is giving the correct dibits out, and not inverse or something.
/*
for (int i = 0; i < 98; i++) {
n = i * 2;
if (n >= 98) n += 68;
bool b1 = data[n] != 0x0;
n = i * 2 + 1;
if (n >= 98) n += 68;
bool b2 = data[n] != 0x0;
if (!b1 && b2)
dibit = +3; // 1 - 01
else if (!b1 && !b2)
dibit = +1; // 0 - 00
else if (b1 && !b2)
dibit = -1; // 2 - 10
else
dibit = -3; // 3 - 11
*/
//Keep it simple!
for (int i = 0; i < 98; i++)
{
n = INTERLEAVE_TABLE[97-i];
//n = i;
if (data[i] == 0)
{
dibits[n] = 1; //1
}
if (data[i] == 1)
{
dibits[n] = 3; //3
}
if (data[i] == 2)
{
dibits[n] = -1; //-1
}
if (data[i] == 3)
{
dibits[n] = -3; //-3
}
}
//n = INTERLEAVE_TABLE[i]; //should this go in reverse?
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
//dibits[n] = dibit; //should this go in reverse too? not sure on this one, but definitely the INTERLEAVE_TABLE
//n = INTERLEAVE_TABLE[97-i]; //should this go in reverse?
//dibits[97-n] = dibit;
//}
}
void CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points)
{
for (unsigned int i = 0U; i < 49U; i++) {
if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1)
points[i] = 0U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1)
points[i] = 1U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3)
points[i] = 2U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3)
points[i] = 3U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1)
points[i] = 4U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1)
points[i] = 5U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3)
points[i] = 6U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3)
points[i] = 7U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3)
points[i] = 8U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3)
points[i] = 9U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1)
points[i] = 10U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1)
points[i] = 11U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3)
points[i] = 12U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3)
points[i] = 13U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1)
points[i] = 14U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1)
points[i] = 15U;
}
}
void CDMRTrellisPointsToDibits(const unsigned char* points, signed char* dibits)
{
for (unsigned int i = 0U; i < 49U; i++) {
switch (points[i]) {
case 0U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = -1;
break;
case 1U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = -1;
break;
case 2U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = -3;
break;
case 3U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = -3;
break;
case 4U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = -1;
break;
case 5U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = -1;
break;
case 6U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = -3;
break;
case 7U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = -3;
break;
case 8U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = +3;
break;
case 9U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = +3;
break;
case 10U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = +1;
break;
case 11U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = +1;
break;
case 12U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = +3;
break;
case 13U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = +3;
break;
case 14U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = +1;
break;
default:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = +1;
break;
}
}
}
void CDMRTrellisBitsToTribits(const unsigned char* payload, unsigned char* tribits)
{
for (unsigned int i = 0U; i < 48U; i++) {
unsigned int n = 143U - i * 3U;
bool b1 = READ_BIT(payload, n) != 0x00U;
n--;
bool b2 = READ_BIT(payload, n) != 0x00U;
n--;
bool b3 = READ_BIT(payload, n) != 0x00U;
unsigned char tribit = 0U;
tribit |= b1 ? 4U : 0U;
tribit |= b2 ? 2U : 0U;
tribit |= b3 ? 1U : 0U;
//tribits[i] = tribit;
}
tribits[48U] = 0U;
}
bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload)
{
assert(data != NULL);
assert(payload != NULL);
unsigned char tribits[49U];
for (short i = 0; i < 49; i++)
{
tribits[i] = 0; //initialize with 0 values so we know later on if these values are actually being assigned or not
}
if (1 == 2)
{
fprintf (stderr, "\n Raw Trellis Dibits inside Decoder\n ");
for (short i = 0; i < 98; i++)
{
fprintf (stderr, "#%d [%0d] ", i, data[i]);
}
}
signed char dibits[98U];
CDMRTrellisDeinterleave(data, dibits);
if (1 == 2)
{
fprintf (stderr, "\n Trellis Deinterleaved Dibits inside Decoder (converted to signed)\n ");
for (short i = 0; i < 98; i++)
{
fprintf (stderr, "#%d [%d] ", i, dibits[i]); //signed char, values should be -3, -1, 1, 3 only
}
}
unsigned char points[49U];
unsigned char reverse_points[49U];
CDMRTrellisDibitsToPoints(dibits, points);
//maybe keep point 49 at 49, since its the flush?
//fprintf (stderr, "\n Trellis Reverse Points inside Decoder\n ");
for (short i = 0; i < 49; i++)
{
reverse_points[i] = points[48-i];
//fprintf (stderr, "#%d [%02u] ", i, reverse_points[i]);
}
//reverse_points[48] = points[48];
//fprintf (stderr, "#%d [%02u] ", 48, reverse_points[48]);
if (1 == 2)
{
fprintf (stderr, "\n Trellis Points inside Decoder\n ");
for (short i = 0; i < 49; i++)
{
fprintf (stderr, "#%d [%02u] ", i, points[i]);
}
}
// Check the original code
unsigned int failPos = CDMRTrellisCheckCode(points, tribits);
//unsigned int failPos = CDMRTrellisCheckCode(reverse_points, tribits); //stack smashing detected terminated
if (1 == 2)
{
fprintf (stderr, "\n Check Code Trellis Tribits inside Decoder\n ");
for (short i = 0; i < 49; i++)
{
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
}
}
if (failPos == 999U)
{
CDMRTrellisTribitsToBits(tribits, payload);
if (1 == 2)
{
fprintf (stderr, "\nTrellis Payload Tribits\n %s ", KCYN);
for (short i = 0; i < 49; i++)
{
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
}
}
if (1 == 2)
{
fprintf (stderr, "\nTrellis Payload Tribits to Bytes inside Decoder\n %s ", KCYN);
for (short i = 0; i < 18; i++)
{
fprintf (stderr, "[%02X]", payload[i]);
}
fprintf (stderr,"%s", KNRM); //change back to normal
}
return true;
}
unsigned char savePoints[49U];
for (unsigned int i = 0U; i < 49U; i++)
savePoints[i] = points[i];
//savePoints[i] = reverse_points[i];
bool ret = CDMRTrellisFixCode(points, failPos, payload);
//bool ret = CDMRTrellisFixCode(reverse_points, failPos, payload);
if (ret){
if (1 == 2)
{
fprintf (stderr, "\n if return Trellis Tribits inside Decoder\n ");
for (short i = 0; i < 49; i++)
{
fprintf (stderr, "#%d [%0u] ", i, tribits[i]); //shouldn't have any values greater that 0x7?
}
}
if (1 == 2)
{
fprintf (stderr, "\nTrellis Payload Tribits to Bits fix return true\n "); //this one seems to be happening
for (short i = 0; i < 18; i++)
{
fprintf (stderr, "[%02X]", payload[i]);
}
}
return true; }
if (failPos == 0U)
{
if (1 == 2)
{
fprintf (stderr, "\nTrellis Payload Tribits to Bytes failPos == 0U\n ");
for (short i = 0; i < 18; i++)
{
fprintf (stderr, "[%02X]", payload[i]);
}
}
return false; }
// Backtrack one place for a last go
return CDMRTrellisFixCode(savePoints, failPos - 1U, payload);
}

View File

@@ -630,7 +630,7 @@ processX2TDMAvoice (dsd_opts * opts, dsd_state * state)
{
if ((eeei == 0) && (aiei == 0))
{
processP25lcw (opts, state, lcformat, mfid, lcinfo);
// processP25lcw (opts, state, lcformat, mfid, lcinfo);
}
if (opts->p25enc == 1)
{

1299
src/ysf.c

File diff suppressed because it is too large Load Diff

BIN
tone24.wav Normal file

Binary file not shown.

BIN
tone48.wav Normal file

Binary file not shown.

BIN
tone8.wav Normal file

Binary file not shown.

4
virtualsink.sh Normal file
View File

@@ -0,0 +1,4 @@
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