diff --git a/README.md b/README.md index 96f0e83..1bc2558 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,75 @@ -# Digital Speech Decoder - Florida Man Edition -This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/dsd "szechyjs") RTL branch and some of my own additions, along with a few tweaks from the [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve") branch as well. NXDN voice decoding is currently working a lot better, thanks to the latter, although I have yet to explore the expanded NXDN or DMR decoding he has laid out. That is a goal. I have also implemented a few more RTL options, including rtl device gain, PPM error, device index selection, squelch, VFO bandwidth, and a UDP remote that works like the old rtl_udp fork, although its currently limited to changing frequency and squelch. The goal is to integrate this project into [EDACS-FM](https://github.com/lwvmobile/edacs-fm "EDACS-FM") but I also want it to be its own standalone project. +# Digital Speech Decoder - Florida Man Edition +This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/dsd "szechyjs") RTL branch and some of my own additions, along with portions of DMR and NXDN code from the [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve") branch as well. This code also borrows snippets, inspiration, and ideas from other open source works including [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25"), [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), and [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"). 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, and hrh17 for the many hours of wav samples submitted by them. + +## 2022.05.05 Update ## +I have successfully added a DMR Stereo method for listening to voice audio in both TDMA channels/slots simultaneously. This method will also allow for data decoding in the opposite slot if only one voice call is active, allowing the user not to miss any useful information in the second slot while the previous slot is in use. DMR Stereo also has vastly improved handling of MS/Simplex voice decoding and (hit or miss) MS data decoding. To call this method, see the example below. The old method of decoding DMR is also included and is stil the default for the time being, but the DMR Stereo method is working well, users are encouraged to try both methods and find the one that is suitable for them. New commands include: +``` +-T Enable DMR 'TDMA' Stereo +-F Enable Passive Frame Sync +``` +Please note, for the time being, any MBE file saving, WAV file saving, or MBE payloads are disabled while using DMR Stereo. These features are still present in the default DMR handling and other voice decoder options and will be re- integrated into DMR Stereo in the future. DMR Stereo will also need to be enabled to handle DMR MS/Simplex voice, as it was removed from the default method due to poor performance. + +Use Passive Frame Sync if voice in both slots becomes choppy or skips. Using Passive Sync may cause wonky audio though, depends on quality of signal and bit errors present. + ![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme.png) -## Example Usage - NCurses Terminal and Log Console to log file -`./dsd -N 2> voice.log` +![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme2.png) -in second terminal, same folder, run: +### Example Usage and Note! +`dsd` or `./dsd` may need to be used in your usage, depending on if you are running it from the build folder, or if you have run make install. You will need to tweak the examples to your particular usage. Users can always check `dsd -h` for help and all command line switches to use. + +`dsd` is all you need to run for pulse input, pulse output, and auto detect for DMR, P25P1, D-STAR, and X2-TDMA decoding. To use other decoding methods which cannot be auto detected, please use the following command line switches. + +``` +-fi NXDN48 +-fn NXDN96 +-fp ProVoice +-fm dPMR, also may need to use -xd if inverted dPMR. +-fr DMR, also may need to use -xr if inverted DMR, use -T for Stereo, and -F for passive sync +-f1 P25P1 +-fx X2-TDMA +``` + +## Example Usage - New DMR Stereo, Ncurses Terminal, Pulse Input/Output, and Log Console to file +`dsd -fr -T -Z -N 2> voice.log` + +and in a second terminal tab, same folder, run `tail -n 40 -f voice.log` -## Example Usage - RTL +## Example Usage - RTL2832 Dongle Input `dsd -fi -i rtl -c 154.9875M -P -2 -D 1 -G 36 -L 70 -U 6021 -Y 12` ``` -i rtl to use rtl_fm (default is -i pulse for pulse audio) --o pulse to set output to pulse audio (is default anyways) +-o pulse to set output to pulse audio (excluded, is default anyways) -c Set frequency --P set PPM error +-P set PPM error (default = 0) --D set device index number +-D set device index number (default = 0; first device detected) -G set device gain (0-49) (default = 0 Auto Gain) --L set rtl squelch to 25 +-L set rtl squelch to 25 (default = 0; off) --V set RTL sample 'volume' multiplier +-U set UDP port for rtl_fm remote control (default = 6020) --U set UDP port for rtl_fm remote control - --Y 12 set rtl VFO bandwidth in kHz, (default = 48)(6, 8, 12, 16, 24, 48) +-Y 12 set rtl VFO bandwidth in kHz, (default = 12)(6, 8, 12, 16, 24, 48) ``` - -### Note - -`dsd` and `./dsd` may need to be used in your usage, depending on if you are running it from the build folder, or if you have run make install. You will need to tweak the examples to your particular usage - - -## Example Pulse Audio Input and Pulse Audio Output, Autodetect Frame Type -`dsd` or `./dsd` -``` -Yes, it really is this simple now - --fa Auto-detect frame type, is default - -sans NXDN, dPMR, or Provoice, need to specify -fp, -fd, -fi, or -fn respectively -pulse audio is set as default input and output methods - -``` -## Example STDIN UDP from GQRX or SDR++, output to Pulse Audio, and save wav files -`socat stdio udp-listen:7355 | dsd -fi -i - -o pulse -w nxdn.wav` +## Example STDIN UDP from GQRX or SDR++, output to Pulse Audio, and append decoded audio to wav file +`socat stdio udp-listen:7355 | dsd -fi -i - -w nxdn.wav` ## Example Usage - Extra Information for Academic Study and Logging +Be sure to create a folder called MBE first and run + `dsd -d ./MBE/ -Z -pu 2>> voice.log` -in second terminal, same folder, run: +and in a second terminal tab, same folder, run `tail -n 40 -f voice.log` @@ -67,7 +78,7 @@ The Current list of objectives include: 1. ~~Random Tinkering~~ More Random Tinkering -2. ~~Implemented Pulse Audio~~ Remove PortAudio, improve Pulse Audio for stereo output and channel/slot separation. +2. ~~Implemented Pulse Audio~~ Remove PortAudio, ~~improved Pulse Audio for stereo output and channel/slot separation~~ 3. ~~Improve NXDN and DMR support~~ Continue to improve ~~NXDN and DMR~~ all data and voice decoding. @@ -77,9 +88,9 @@ The Current list of objectives include: ## How to clone, check out, and build this branch -### Ubuntu 20.04/LM20/Debian Bullseye or Newer: +### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer: -Using the included install.sh should make for a simple and painless clone, build, and install on newer Debian or Ubuntu based system. Simply acquire or copy the script, and run it. +Using the included install.sh should make for a simple and painless clone, build, and install on newer Debian or Ubuntu based system. Simply acquire or copy the script, and run it. Update: Ubuntu 22.04 has been tested working with the installer script and use. ``` wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/pulseaudio/install.sh @@ -92,8 +103,7 @@ The above install.sh should now function on older system types. You can elect to ## Manual Install -First, install dependency packages. This guide will assume you are using Ubuntu 20.04 based distros. Check your package manager for equivalent packages if different. PortAudio is not currently used in this build, and is disabled in CMakeLists.txt, you can re-enable it if you wish, but it isn't recommended unless you have a very specific reason to do so. Some of these dependencies are not currently be used, but may be used in future builds. - +First, install dependency packages. This guide will assume you are using Ubuntu 20.04 based distros. Check your package manager for equivalent packages if different. PortAudio is not used in this build! ``` sudo apt update diff --git a/dsd-fme.png b/dsd-fme.png index f770f2d..d45c8d4 100644 Binary files a/dsd-fme.png and b/dsd-fme.png differ diff --git a/dsd-fme2.png b/dsd-fme2.png new file mode 100644 index 0000000..396993b Binary files /dev/null and b/dsd-fme2.png differ diff --git a/include/dsd.h b/include/dsd.h index 48319a0..4660580 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -17,6 +17,17 @@ * PERFORMANCE OF THIS SOFTWARE. */ + //pretty pretty colors + + #define KNRM "\x1B[0m" + #define KRED "\x1B[31m" + #define KGRN "\x1B[32m" + #define KYEL "\x1B[33m" + #define KBLU "\x1B[34m" + #define KMAG "\x1B[35m" + #define KCYN "\x1B[36m" + #define KWHT "\x1B[37m" + #include "config.h" #include #include @@ -67,13 +78,11 @@ //look into making this not required by doing ifdef, make new c file for methods, and CLI case option for ncurses terminal #include //move this stuff to dsd.h #include //move this stuff to dsd.h -/* - * global variables - */ +// +// static volatile int exitflag; -//borrow from LEH typedef struct { uint8_t RFChannelType; @@ -148,8 +157,6 @@ typedef struct } NxdnElementsContent_t; -//LEH DMR - enum { MODE_UNENCRYPTED, @@ -230,8 +237,8 @@ typedef struct FullLinkControlPDU_t FullLC; } TimeSlotVoiceSuperFrame_t; -//end borrow from LEH -//LEH dPMR + +//dPMR /* Could only be 2 or 4 */ #define NB_OF_DPMR_VOICE_FRAME_TO_DECODE 2 @@ -293,11 +300,13 @@ typedef struct int audio_out_type; // 0 for device, 1 for file, 2 for portaudio int split; int playoffset; + int playoffsetR; char mbe_out_dir[1024]; char mbe_out_file[1024]; char mbe_out_path[1024]; FILE *mbe_out_f; float audio_gain; + float audio_gainR; int audio_out; char wav_out_file[1024]; SNDFILE *wav_out_f; @@ -337,27 +346,35 @@ typedef struct int pulse_raw_rate_out; int pulse_digi_rate_in; int pulse_digi_rate_out; + //int pulse_digi_rate_outR; int pulse_raw_in_channels; int pulse_raw_out_channels; int pulse_digi_in_channels; int pulse_digi_out_channels; + //int pulse_digi_out_channelsR; int pulse_flush; pa_simple *pulse_raw_dev_in; pa_simple *pulse_raw_dev_out; pa_simple *pulse_digi_dev_in; pa_simple *pulse_digi_dev_out; + pa_simple *pulse_digi_dev_outR; int use_ncurses_terminal; int reset_state; int payload; char output_name[1024]; - //LEH DMR Stuff + int EncryptionMode; - //LEH dPMR stuff unsigned int dPMR_curr_frame_is_encrypted; int dPMR_next_part_of_superframe; int inverted_dpmr; int frame_dpmr; + // + short int dmr_stereo; + // + int frame_ysf; + int inverted_ysf; //not sure if ysf comes in inverted or not, but signal could if IQ flipped + short int aggressive_framesync; //set to 1 for more aggressive framesync, 0 for less aggressive } dsd_opts; @@ -365,6 +382,8 @@ typedef struct { int *dibit_buf; int *dibit_buf_p; + int *dmr_payload_buf; //try loading up a small amount to buffer, 144 or 288? + int *dmr_payload_p; //position for payload buffer int repeat; short *audio_out_buf; short *audio_out_buf_p; @@ -414,10 +433,14 @@ typedef struct char tg[25][16]; int tgcount; int lasttg; + int lasttgR; int lastsrc; + int lastsrcR; int nac; int errs; int errs2; + int errsR; + int errs2R; int mbe_file_type; int optind; int numtdulc; @@ -425,25 +448,38 @@ typedef struct char slot0light[8]; //char slot1light[8]; float aout_gain; + float aout_gainR; float aout_max_buf[200]; + float aout_max_bufR[200]; float *aout_max_buf_p; + float *aout_max_buf_pR; int aout_max_buf_idx; + int aout_max_buf_idxR; int samplesPerSymbol; int symbolCenter; char algid[9]; char keyid[17]; int currentslot; + int hardslot; mbe_parms *cur_mp; mbe_parms *prev_mp; mbe_parms *prev_mp_enhanced; + mbe_parms *cur_mp2; + mbe_parms *prev_mp2; + mbe_parms *prev_mp_enhanced2; int p25kid; int payload_algid; + int payload_algidR; int payload_keyid; + int payload_keyidR; int payload_mfid; + int payload_mfidR; int payload_mi; + int payload_miR; unsigned long long int K; unsigned int debug_audio_errors; + unsigned int debug_audio_errorsR; unsigned int debug_header_errors; unsigned int debug_header_critical_errors; @@ -459,17 +495,6 @@ typedef struct //input sample buffer for monitoring Input short input_sample_buffer; //HERE HERE short pulse_raw_out_buffer; //HERE HERE - //float *input_sample_buffer; //HERE HERE - short dibit_to_hex_buf; - // state->sr_0 shift registers - short hexbuf; - unsigned long long sr_0; //64-bit shift registers for pushing decoded binary or dibit data - unsigned long long sr_1; //384 - unsigned long long sr_2; // - unsigned long long sr_3; // - unsigned long long sr_4; // - unsigned long long sr_5; // - unsigned long long sr_6; // unsigned int dmr_color_code; unsigned int nxdn_last_ran; @@ -478,10 +503,9 @@ typedef struct unsigned int nxdn_cipher_type; unsigned int nxdn_key; char nxdn_call_type[1024]; - char dmr_callsign[4][99]; //plenty of room in case of overflow; - char dmr_lrrp[6][9999]; + char dmr_callsign[2][6][99]; //plenty of room in case of overflow; + char dmr_lrrp[2][6][9999]; - //borrow from LEH NxdnSacchRawPart_t NxdnSacchRawPart[4]; NxdnFacch1RawPart_t NxdnFacch1RawPart[2]; NxdnFacch2RawPart_t NxdnFacch2RawPart; @@ -492,8 +516,7 @@ typedef struct char ambe_ciphered[49]; char ambe_deciphered[49]; - //end borrow - //LEH DMR struff + unsigned int color_code; unsigned int color_code_ok; unsigned int PI; @@ -504,6 +527,9 @@ typedef struct unsigned int dmr_fid; unsigned int dmr_so; + unsigned int dmr_fidR; + unsigned int dmr_soR; + char slot1light[8]; char slot2light[8]; int directmode; @@ -511,10 +537,11 @@ typedef struct TimeSlotVoiceSuperFrame_t TS2SuperFrame; char dmr_branding[25]; - uint8_t dmr_12_rate_sf[36]; //going three frames deep - uint8_t dmr_34_rate_sf[54]; //going three frames deep + uint8_t dmr_12_rate_sf[2][60]; //going five frames deep by 12 bytes //[slot][value] + uint8_t dmr_34_rate_sf[2][64]; //going four frames deep by 16 bytes //[slot][value] + int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame + - //LEH dPMR stuff dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame; //These flags are used to known the DMR frame @@ -539,6 +566,15 @@ typedef struct unsigned char * dpmr_target_id; int dpmr_color_code; + short int dmr_stereo; //need state variable for upsample function + short int dmr_ms_rc; + short int dmr_ms_mode; + unsigned int dmrburstL; + unsigned int dmrburstR; + + //dstar header for ncurses + unsigned char dstarradioheader[41]; + #ifdef TRACE_DSD char debug_prefix; char debug_prefix_2; @@ -555,6 +591,10 @@ typedef struct /* * Frame sync patterns */ + +#define FUSION_SYNC "31111311313113131131" //HA! +#define INV_FUSION_SYNC "13333133131331313313" //HA! + #define INV_P25P1_SYNC "333331331133111131311111" #define P25P1_SYNC "111113113311333313133333" @@ -568,14 +608,6 @@ typedef struct #define DSTAR_SYNC "313131313133131113313111" #define INV_DSTAR_SYNC "131313131311313331131333" -//bogus nxdnn data syncs to troubleshoot -/* -#define NXDN_MS_DATA_SYNC "33333313133113131111333333333111" -#define INV_NXDN_MS_DATA_SYNC "11133331313113313133331113333331" -#define INV_NXDN_BS_DATA_SYNC "33331111313113313133331313333333" -#define NXDN_BS_DATA_SYNC "11113333131331131311113133333333" -//end bogus nxdn data syncs -*/ #define NXDN_MS_DATA_SYNC "313133113131111333" #define INV_NXDN_MS_DATA_SYNC "131311331313333111" #define INV_NXDN_BS_DATA_SYNC "131311331313333131" @@ -589,64 +621,52 @@ typedef struct #define DMR_BS_VOICE_SYNC "131111333113313313113313" #define DMR_MS_DATA_SYNC "311131133313133331131113" #define DMR_MS_VOICE_SYNC "133313311131311113313331" -//borrow extra syncs from LEH + +//inversion testing on MS +//#define DMR_MS_DATA_SYNC "133313311131311113313331" +//#define DMR_MS_VOICE_SYNC "311131133313133331131113" + +#define DMR_RC_DATA_SYNC "131331111133133133311313" + #define DMR_DIRECT_MODE_TS1_DATA_SYNC "331333313111313133311111" #define DMR_DIRECT_MODE_TS1_VOICE_SYNC "113111131333131311133333" #define DMR_DIRECT_MODE_TS2_DATA_SYNC "311311111333113333133311" #define DMR_DIRECT_MODE_TS2_VOICE_SYNC "133133333111331111311133" -//end LEH + #define INV_PROVOICE_SYNC "31313111333133133311331133113311" #define PROVOICE_SYNC "13131333111311311133113311331133" #define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311" #define PROVOICE_EA_SYNC "31131311331331111133131311311133" -//LEH dPMR -/* dPMR Frame Sync 1 - 48 bits sequence - * HEX : 57 FF 5F 75 D5 77 - * Binary : 0101 0111 1111 1111 0101 1111 0111 0101 1101 0101 0111 0111 - * Dibit : 1 1 1 3 3 3 3 3 1 1 3 3 1 3 1 1 3 1 1 1 1 3 1 3 */ - #define DPMR_FRAME_SYNC_1 "111333331133131131111313" - -/* dPMR Frame Sync 2 - 24 bits sequence - * HEX : 5F F7 7D - * Binary : 0101 1111 1111 0111 0111 1101 - * Dibit : 1 1 3 3 3 3 1 3 1 3 3 1 */ #define DPMR_FRAME_SYNC_2 "113333131331" - -/* dPMR Frame Sync 3 - 24 bits sequence - * HEX : 7D DF F5 - * Binary : 0111 1101 1101 1111 1111 0101 - * Dibit : 1 3 3 1 3 1 3 3 3 3 1 1 */ #define DPMR_FRAME_SYNC_3 "133131333311" - -/* dPMR Frame Sync 4 - 48 bits sequence - * HEX : FD 55 F5 DF 7F DD - * Binary : 1111 1101 0101 0101 1111 0101 1101 1111 0111 1111 1101 1101 - * Dibit : 3 3 3 1 1 1 1 1 3 3 1 1 3 1 3 3 1 3 3 3 3 1 3 1 */ #define DPMR_FRAME_SYNC_4 "333111113311313313333131" -//#define DPMR_FRAME_SYNC_4 "111333331133131131111313" /* dPMR Frame Sync 1 to 4 - Inverted */ #define INV_DPMR_FRAME_SYNC_1 "333111113311313313333131" #define INV_DPMR_FRAME_SYNC_2 "331111313113" #define INV_DPMR_FRAME_SYNC_3 "311313111133" #define INV_DPMR_FRAME_SYNC_4 "111333331133131131111313" -//#define INV_DPMR_FRAME_SYNC_4 "333111113311313313333131" -// /* * function prototypes */ void processDMRdata (dsd_opts * opts, dsd_state * state); void processDMRvoice (dsd_opts * opts, dsd_state * state); +void dmrBSBootstrap (dsd_opts * opts, dsd_state * state); +void dmrBS (dsd_opts * opts, dsd_state * state); +void dmrMS (dsd_opts * opts, dsd_state * state); +void dmrMSData (dsd_opts * opts, dsd_state * state); +void dmrMSBootstrap (dsd_opts * opts, dsd_state * state); void processdPMRvoice (dsd_opts * opts, dsd_state * state); void processAudio (dsd_opts * opts, dsd_state * state); -void playRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE +void processAudioR (dsd_opts * opts, dsd_state * state); void openPulseInput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet void openPulseOutput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state); void openAudioOutDevice (dsd_opts * opts, int speed); void openAudioInDevice (dsd_opts * opts); @@ -695,10 +715,11 @@ void processProVoice (dsd_opts * opts, dsd_state * state); 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 short dmr_filter(short sample); short nxdn_filter(short sample); -//borrow from LEH for testing 'improved NXDN detection' + int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr); /* Global functions */ //also borrowed uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength); @@ -711,7 +732,7 @@ void ncursesOpen (); void ncursesPrinter (dsd_opts * opts, dsd_state * state); void ncursesClose (); //endif ncurses -//borrow from LEH + /* NXDN frame decoding functions */ void ProcessNXDNFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted); void ProcessNxdnRCCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted); @@ -722,7 +743,7 @@ void ProcessNXDNIdleData (dsd_opts * opts, dsd_state * state, uint8_t Inverted); void ProcessNXDNFacch1Data (dsd_opts * opts, dsd_state * state, uint8_t Inverted); void ProcessNXDNUdchData (dsd_opts * opts, dsd_state * state, uint8_t Inverted); //end borrow -//borrow from LEH + /* NXDN functions */ void CNXDNConvolution_start(void); void CNXDNConvolution_decode(uint8_t s0, uint8_t s1); @@ -751,7 +772,7 @@ uint16_t CRC12BitNXDN(uint8_t * BufferIn, uint32_t BitLength); uint8_t CRC6BitNXDN(uint8_t * BufferIn, uint32_t BitLength); void ScrambledNXDNVoiceBit(int * LfsrValue, char * BufferIn, char * BufferOut, int NbOfBitToScramble); -//LEH dPMR + void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state); void printdPMRAmbeVoiceSample(dsd_opts * opts, dsd_state * state); void printdPMRRawVoiceFrame (dsd_opts * opts, dsd_state * state); @@ -762,7 +783,7 @@ uint8_t CRC7BitdPMR(uint8_t * BufferIn, uint32_t BitLength); uint8_t CRC8BitdPMR(uint8_t * BufferIn, uint32_t BitLength); void ConvertAirInterfaceID(uint32_t AI_ID, uint8_t ID[8]); int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]); -//LEH DMR + void ProcessDMR (dsd_opts * opts, dsd_state * state); void DMRDataFrameProcess(dsd_opts * opts, dsd_state * state); void DMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state); @@ -797,6 +818,7 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); +void ProcessUnifiedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); void Hamming_7_4_init(); @@ -836,10 +858,8 @@ void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits); bool QR_16_7_6_decode(unsigned char *rxBits); void InitAllFecFunction(void); - -//end borrow from LEH - void resetState (dsd_state * state); +void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]); #ifdef __cplusplus extern "C" { @@ -860,6 +880,8 @@ 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); + + #ifdef __cplusplus } #endif diff --git a/include/dstar_header.h b/include/dstar_header.h index 9723fbf..0b8e86d 100644 --- a/include/dstar_header.h +++ b/include/dstar_header.h @@ -2,5 +2,5 @@ #ifndef _DSTAR_HEADER_H #define _DSTAR_HEADER_H -void dstar_header_decode(int radioheaderbuffer[660]); -#endif /* _DSTAR_HEADER_H */ \ No newline at end of file +//void dstar_header_decode(int radioheaderbuffer[660]); +#endif /* _DSTAR_HEADER_H */ diff --git a/src/dmr_bs.c b/src/dmr_bs.c new file mode 100644 index 0000000..fff2fae --- /dev/null +++ b/src/dmr_bs.c @@ -0,0 +1,465 @@ +#include "dsd.h" +#include "dmr_const.h" + +//A subroutine for processing each TDMA frame individually to allow for +//processing voice and/or data on both BS slots (channels) simultaneously +void dmrBS (dsd_opts * opts, dsd_state * state) +{ + int i, j, k, l, dibit; + int *dibit_p; + char ambe_fr[4][24] = {0}; + char ambe_fr2[4][24] = {0}; + char ambe_fr3[4][24] = {0}; + char t_ambe_fr[4][24] = {9}; + char t_ambe_fr2[4][24] = {9}; + char t_ambe_fr3[4][24] = {9}; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[48]; + char cachdata[13] = {0}; + int mutecurrentslot; + int msMode; + char cc[4]; + unsigned char EmbeddedSignalling[16]; + int EmbeddedSignallingOk; + unsigned int internalcolorcode; + int internalslot; + char redundancyA[36]; + char redundancyB[36]; + unsigned short int vc1; + unsigned short int vc2; + + //add time to mirror printFrameSync + time_t now; + char * getTime(void) //get pretty hh:mm:ss timestamp + { + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; + } + + //Init the superframe buffers + //memset(&state->TS1SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t)); + //memset(&state->TS2SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t)); + + //Init the color code status + state->color_code_ok = 0; + + vc1 = 2; + vc2 = 2; + + short int loop = 1; + short int skipcount = 0; + + //Run Loop while the getting is good + while (loop == 1) { + + // CACH + internalslot = -1; //reset here so we know if this value is being set properly + for(i = 0; i < 12; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cachdata[i] = dibit; + state->dmr_stereo_payload[i] = dibit; + if(i == 2) + { + state->currentslot = (1 & (dibit >> 1)); + internalslot = (1 & (dibit >> 1)); + } + } + + //Setup for first AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //First AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+12] = dibit; + redundancyA[i] = dibit; + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //check for repetitive data if caught in a 'no carrier' loop? Just picking random values. + //this will test for no carrier (input signal) and return us to no sync state if necessary + if (redundancyA[16] == redundancyB[16] && redundancyA[27] == redundancyB[27] && + redundancyA[01] == redundancyB[01] && redundancyA[32] == redundancyB[32] && + redundancyA[03] == redundancyB[03] && redundancyA[33] == redundancyB[33] && + redundancyA[13] == redundancyB[13] && redundancyA[07] == redundancyB[07] ) + { + goto END; + } + // end redundancy test, set B to A + for(i = 0; i < 36; i++) + { + redundancyB[i] = redundancyA[i]; + } + + //Setup for Second AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Second AMBE Frame, First Half 18 dibits just before Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+48] = dibit; + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //short int l = 0; //do I still use this? + // signaling data or sync + for(i = 0; i < 24; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+66] = dibit; + syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 + syncdata[(2*i)+1] = (1 & dibit); // bit 0 + sync[i] = (dibit | 1) + 48; + + if (i < 4 || i > 19) // + { + EmbeddedSignalling[2*i] = (1 & (dibit >> 1)); // bit 1 + EmbeddedSignalling[2*i+1] = (1 & dibit); // bit 0 + } + + //Used for ProcessVoiceBurstSync + if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E + { + /* Time slot 1 superframe buffer filling => SYNC data */ + state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 + state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0 + } + if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E + { + /* Time slot 2 superframe buffer filling => SYNC data */ + state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 + state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0 + } + + } + + sync[24] = 0; + EmbeddedSignallingOk = -1; + if(QR_16_7_6_decode(EmbeddedSignalling)) + { + EmbeddedSignallingOk = 1; + } + + internalcolorcode = 69; //set so we know if this value is being set properly + if(EmbeddedSignallingOk == 1) + { + state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + state->color_code_ok = EmbeddedSignallingOk; + + //Power Indicator, not the other PI (header) + state->PI = (unsigned int)EmbeddedSignalling[4]; + state->PI_ok = EmbeddedSignallingOk; + + //Link Control Start Stop Indicator + state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); + state->LCSS_ok = EmbeddedSignallingOk; + + } + else skipcount++; + + //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+90] = dibit; + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //Setup for Third AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Third AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+108] = dibit; + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //reset vc counters to 1 if new voice sync frame on each slot + if ( (strcmp (sync, DMR_BS_VOICE_SYNC) == 0) ) + { + if (internalslot == 0) + { + vc1 = 1; + } + if (internalslot == 1) + { + vc2 = 1; + } + } + + //check for sync pattern here after collected the rest of the payload, decide what to do with it + if ( (strcmp (sync, DMR_BS_DATA_SYNC) == 0) ) + { + fprintf (stderr,"%s ", getTime()); + if (internalslot == 0) + { + sprintf(state->slot1light, "[slot1]"); + sprintf(state->slot2light, " slot2 "); + //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | Data ", state->color_code); + fprintf (stderr,"Sync: +DMR "); + //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame + vc1 = 1; + } + if (internalslot == 1) + { + sprintf(state->slot2light, "[slot2]"); + sprintf(state->slot1light, " slot1 "); + //fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | Data ", state->color_code); + fprintf (stderr,"Sync: +DMR "); + //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame + vc2 = 1; + } + processDMRdata (opts, state); + skipcount++; //after 6 data frames, drop back to getFrameSync and process subsequent data with processDMRdata + goto SKIP; + } + + if( (strcmp (sync, DMR_BS_DATA_SYNC) != 0) ) //only play voice no data sync // || (strcmp (sync, DMR_MS_DATA_SYNC) != 0) + { + if (EmbeddedSignallingOk == 0) + { + //goto END; + } + skipcount = 0; //reset skip count if processing voice frames + fprintf (stderr,"%s ", getTime()); + if (internalslot == 0) + { + state->dmrburstL = 16; //use 16 for Voice? + fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc1); + } + + if (internalslot == 1) + { + state->dmrburstR = 16; //use 16 for Voice? + fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc2); + } + if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues) + { + //process voice burst + ProcessVoiceBurstSync(opts, state); + fprintf (stderr, "\n"); + } + if (internalslot == 1 && vc2 == 6) //presumably when full (and no sync issues) + { + //process voice burst + ProcessVoiceBurstSync(opts, state); + fprintf (stderr, "\n"); + } + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if (internalslot == 0) + { + vc1++; + } + if (internalslot == 1) + { + vc2++; + } + } + + // recalibrate center/umid/lmid, not sure this helps or does anything particularly in this case + state->center = ((state->max) + (state->min)) / 2; + state->umid = (((state->max) - state->center) * 5 / 8) + state->center; + state->lmid = (((state->min) - state->center) * 5 / 8) + state->center; + + //Escape conditions to break the loop + //7 seems optimal, allows for an extra frame each in case of late entry on dual voices + if ( (vc1 > 7 && vc2 > 7) ) + { + goto END; + } + //14 probably allows a few more in case of a bit of jitter but eventually breaks loop (1 second?) + if ( (vc1 > 14 || vc2 > 14) ) + { + goto END; + } + //using these conditions may cause excessive resyncs IF bad signal, + //but still better than getting stuck in a wonk wonk loop for too long. + //set for more aggressive or less aggressive resync during accumulated playback errs + if (opts->aggressive_framesync == 1) + { + //errors caused due to playing MBE files out of sync, break loop + if (state->errs > 2 || state->errsR > 2) + { + //goto END; // + } + //errors caused due to playing MBE files out of sync, break loop + if (state->errs2 > 4 || state->errs2R > 4) + { + goto END; // + } + } + + //earlier skip conditions teleport us here to process further skip conditions before restarting while loop + SKIP: + if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with processDMRdata + { + goto END; + } + + //since we are in a while loop, run ncursesPrinter here. + if (opts->use_ncurses_terminal == 1) + { + ncursesPrinter(opts, state); + } + + } // while loop + //Teleport here on END condition, set or reset variables and return to look for new frame sync + END: + state->dmr_stereo = 0; + state->errs2R = 0; + state->errs2 = 0; +} + +//Only process 2nd half voice payload (3rd frame) and then jump to full BS decoding +void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) +{ + int i, j, k, l, dibit; + int *dibit_p; + char ambe_fr[4][24] = {0}; + char ambe_fr2[4][24] = {0}; + char ambe_fr3[4][24] = {0}; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[48]; + char cachdata[13] = {0}; + int mutecurrentslot; + int msMode; + char cc[4]; + unsigned char EmbeddedSignalling[16]; + unsigned int EmbeddedSignallingOk; + + //add time to mirror printFrameSync + time_t now; + char * getTime(void) //get pretty hh:mm:ss timestamp + { + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; + } + + //skip the 18 dibits of the 2nd frame, since we can't play only half a frame + skipDibit (opts, state, 18); + + //Setup for Third AMBE Frame + + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Third AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //fprintf (stderr,"\n%s ", getTime()); + fprintf (stderr,"%s ", getTime()); + fprintf (stderr,"Sync: +DMR | Frame Sync | DMRSTEREO | VC1 FS \n"); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode + +} diff --git a/src/dmr_data.c b/src/dmr_data.c index d086880..ccb31f2 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -49,6 +49,12 @@ processDMRdata (dsd_opts * opts, dsd_state * state) bursttype[4] = 0; dibit_p = state->dibit_buf_p - 90; + //using the estimate_symbol method for the dmr_payload_p buffer causes sync + //issues with P25, so only do it when frame_p25p1 == 0, or -fr option + if (opts->frame_p25p1 == 0) //opts->frame_p25p1 == 0 + { + dibit_p = state->dmr_payload_p - 90; + } // CACH for (i = 0; i < 12; i++) @@ -59,6 +65,11 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[i]; + } + //fprintf(stderr, "%X", dibit); cachdata[i] = dibit; if (i == 2) { @@ -79,6 +90,15 @@ processDMRdata (dsd_opts * opts, dsd_state * state) state->slot1light[0] = ' '; state->slot1light[6] = ' '; } + //method to only see data from one slot or the other when data occupies both slots or gets cooked by sync + state->hardslot = 9; //0 to only listen to slot 0 voice, 1 for slot 1, 9 for both + if(state->hardslot != 9 && state->hardslot != state->currentslot) + //if(1==1) + { + fprintf (stderr, " Current Slot = %d", state->currentslot + 1); + fprintf (stderr, "\n"); //line break after breaking out of jail + //goto JUMP; + } } } cachdata[12] = 0; @@ -107,6 +127,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[i+12]; + } trellisdibits[i] = dibit; info[2*i] = (1 & (dibit >> 1)); // bit 1 info[(2*i)+1] = (1 & dibit); // bit 0 @@ -119,6 +143,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[61]; //61, not i+61 + } cc[0] = (1 & (dibit >> 1)); // bit 1 cc[1] = (1 & dibit); // bit 0 SlotType[0] = (1 & (dibit >> 1)); // bit 1 @@ -130,6 +158,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[62]; + } cc[2] = (1 & (dibit >> 1)); // bit 1 cc[3] = (1 & dibit); // bit 0 SlotType[2] = (1 & (dibit >> 1)); // bit 1 @@ -147,6 +179,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) //state + { + dibit = (int)state->dmr_stereo_payload[63]; //(int) + } // burst = (unsigned int)((1 & (dibit >> 1)) << 3); // burst |= (unsigned int)((1 & (dibit >> 0)) << 2); // bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1 @@ -160,6 +196,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) //state + { + dibit = (int)state->dmr_stereo_payload[64]; //(int) + } // burst |= (unsigned int)((1 & (dibit >> 1)) << 1); // burst |= (unsigned int)((1 & (dibit >> 0)) << 0); // bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1 @@ -174,6 +214,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[65]; + } SlotType[8] = (1 & (dibit >> 1)); // bit 1 SlotType[9] = (1 & dibit); // bit 0 @@ -186,6 +230,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[i+66]; //double check these i+ values make sure we are on the right ones + } syncdata[2*i] = (1 & (dibit >> 1)); // bit 1 syncdata[(2*i)+1] = (1 & dibit); // bit 0 sync[i] = (dibit | 1) + 48; @@ -216,6 +264,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) sprintf(state->slot2light, "[slot2]"); } } + else if(strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) { state->currentslot = 0; @@ -236,11 +285,18 @@ processDMRdata (dsd_opts * opts, dsd_state * state) // Slot type - Second part - Parity bit for (i = 0; i < 5; i++) { - dibit = getDibit(opts, state); + if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method + { + dibit = getDibit(opts, state); + } if (opts->inverted_dmr == 1) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[i+90]; //double checked these i+ values make sure we are on the right ones + } SlotType[(i*2) + 10] = (1 & (dibit >> 1)); // bit 1 SlotType[(i*2) + 11] = (1 & dibit); // bit 0 } @@ -250,11 +306,23 @@ processDMRdata (dsd_opts * opts, dsd_state * state) else SlotTypeOk = 0; /* Slot Type parity checked => Fill the color code */ - state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]); + //state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]); + state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0); state->color_code_ok = SlotTypeOk; + //fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); /* Reconstitute the burst type */ + //consider assigning thsi only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]); + if (state->currentslot == 0) + { + state->dmrburstL = burst; + } + if (state->currentslot == 1) + { + state->dmrburstR = burst; + } + /* Reconstitute the burst type */ bursttype[0] = SlotType[4] + '0'; @@ -263,13 +331,55 @@ processDMRdata (dsd_opts * opts, dsd_state * state) bursttype[3] = SlotType[7] + '0'; bursttype[4] = '\0'; + /* //delete this chunk later + if (state->dmr_stereo == 3) //may not need this any longer + { + burst = (state->dmr_stereo_payload[63] << 2) | (state->dmr_stereo_payload[64]); + //this whole split for getting burst and burst type is makes no sense + //why not just use burst + bursttype[0] = (((state->dmr_stereo_payload[63] >> 1) & 1) + '0'); + bursttype[1] = (((state->dmr_stereo_payload[63] >> 0) & 1) + '0'); + bursttype[2] = (((state->dmr_stereo_payload[64] >> 1) & 1) + '0'); + bursttype[3] = (((state->dmr_stereo_payload[64] >> 0) & 1) + '0'); + bursttype[4] = '\0'; + //fprintf(stderr, "BURST1 = %04b ", burst); + } + //figure out why the sync is wrong when dumping the payload to processDMRdata for MS Data + //I think its a conversion issue with the payload(chat) from the dibit buffer (int *) + //actually, its the dibit buffer storing as 1 and 3 only (GFSK) when sync drops + //made a seperate dmr buffer, but still, when sync loss and regain, takes a few syncs to calibrate center/umid/lmid properly + //getting accurate MS data AND leading BS data may be impossible without saving the symbols, calibrating, then going back + //and running the buffer payload, but I honestly don't know right now, probably easier to start from stratch than fix this + if (state->dmr_ms_mode == 7) + { + burst = (unsigned int)((SlotType[4] << 3) | (SlotType[5] << 2) | (SlotType[6] << 1) | SlotType[7]); + bursttype[0] = SlotType[4] + '0'; + bursttype[1] = SlotType[5] + '0'; + bursttype[2] = SlotType[6] + '0'; + bursttype[3] = SlotType[7] + '0'; + bursttype[4] = '\0'; + //fprintf(stderr, "BURST1 = %04b ", burst); + } + + if (state->dmr_stereo == 3) + { + fprintf(stderr, "BURST2 = %b%b%b%b Slot Dump ", SlotType[4], SlotType[5], SlotType[6], SlotType[7] ); + fprintf(stderr, " Slot Dump = "); + for (i = 0; i < 20; i++) + { + fprintf(stderr, "%b", SlotType[i]); + } + fprintf(stderr, "\n "); + } + */ + if (strcmp (bursttype, "0000") == 0) { sprintf(state->fsubtype, " PI Header "); } else if (strcmp (bursttype, "0001") == 0) { - sprintf(state->fsubtype, " VOICE Header "); + sprintf(state->fsubtype, " VOICE LC Header "); } else if (strcmp (bursttype, "0010") == 0) { @@ -316,31 +426,55 @@ processDMRdata (dsd_opts * opts, dsd_state * state) //trellis for (i = 0; i < 49; i++) { - dibit = getDibit(opts, state); + if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method + { + dibit = getDibit(opts, state); + } if (opts->inverted_dmr == 1) { dibit = (dibit ^ 2); } + if (state->dmr_stereo == 1) + { + dibit = (int)state->dmr_stereo_payload[i+95]; //double checked these i+ values make sure we are on the right ones + } trellisdibits[i+49] = dibit; info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1 info[(2*i) + 99] = (1 & dibit); // bit 0 } // Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit) - skipDibit (opts, state, 12 + 49 + 5); + if (state->dmr_stereo == 0) + { + skipDibit (opts, state, 12 + 49 + 5); + } if (opts->errorbars == 1) { /* Print the color code */ - fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); + //if (burst == 0b1001 && state->color_code_ok) //only print on idle for data types, otherwise prints on voice frames. + if (SlotTypeOk == 1) + { + fprintf (stderr, "%s", KCYN); + fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); + fprintf (stderr, "%s", KNRM); + //state->dmr_color_code = state->color_code; + } + else fprintf(stderr, "| "); //if(state->color_code_ok) fprintf(stderr, "(OK) |"); - if(state->color_code_ok) fprintf(stderr, "(CRC OK ) |"); //add line break - else fprintf(stderr, "(CRC ERR) |"); //add line break + if(state->color_code_ok) fprintf(stderr, "| (CRC OK ) |"); //add line break + else + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "| (CRC ERR) |"); + fprintf (stderr, "%s", KNRM); + } //fprintf (stderr, "\n"); //print line break if (strcmp (state->fsubtype, " ") == 0) { - fprintf(stderr, " Unknown burst type: %s", bursttype); + //fprintf(stderr, " Unknown burst type: %s", bursttype); + fprintf(stderr, " Unknown"); } else { @@ -368,6 +502,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = TLC */ case 0b0010: { + //Not sure if I really care about this in the context of what it shows ProcessDmrTerminaisonLC(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -375,6 +510,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = CSBK */ case 0b0011: { + //going to disable until I can find more useful info to present ProcessCSBK(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -386,7 +522,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) break; } - /* Burst = MBC */ + /* Burst = MBC Continuation*/ case 0b0101: { //ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); @@ -410,14 +546,15 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = RATE 3/4 DATA */ case 0b1000: { - //disabled until a viable viterbi/trellis decoding solution is worked out - //Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType); + //need to keep working on improving the trellis decode, but is partially viable now + Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = Slot idle */ case 0b1001: { + if(state->color_code_ok) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok break; } @@ -428,10 +565,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state) break; } - /* Burst = WTF 1101 Type DATA */ + /* Burst = Unified Single Block DATA */ case 0b1101: { - //ProcessWTFData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + //ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -448,5 +585,5 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { fprintf(stderr, "\n"); } - + //JUMP: } /* End processDMRdata() */ diff --git a/src/dmr_ms.c b/src/dmr_ms.c new file mode 100644 index 0000000..5e5aafc --- /dev/null +++ b/src/dmr_ms.c @@ -0,0 +1,672 @@ +#include "dsd.h" +#include "dmr_const.h" + +//A subroutine for processing MS voice +void dmrMS (dsd_opts * opts, dsd_state * state) +{ + //fprintf (stderr, "\n Quick DMR Voice Testing\n"); + int i, j, k, l, dibit; + int *dibit_p; + char ambe_fr[4][24] = {0}; + char ambe_fr2[4][24] = {0}; + char ambe_fr3[4][24] = {0}; + char t_ambe_fr[4][24] = {9}; + char t_ambe_fr2[4][24] = {9}; + char t_ambe_fr3[4][24] = {9}; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[48]; + //standalone inbound rc sync exists on dibits 48-96? + //or 44-92? of each potential payload, middle 10 ms or 30 ms frame + char rcsync[25]; + char rcsyncdata[96]; //96 bit RC sync data + char cachdata[13] = {0}; + int mutecurrentslot; + int msMode; + char cc[4]; + unsigned char EmbeddedSignalling[16]; + int EmbeddedSignallingOk; + unsigned int internalcolorcode; + int internalslot; + int activeslot; + char redundancyA[36]; + char redundancyB[36]; + unsigned short int vc1; + unsigned short int vc2; + //add time to mirror printFrameSync + time_t now; + char * getTime(void) //get pretty hh:mm:ss timestamp + { + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; + } + + //Init the color code status + state->color_code_ok = 0; + + vc1 = 2; + vc2 = 2; + + short int loop = 1; + short int skipcount = 0; + + //Hardset variables for MS + state->currentslot = 0; + internalslot = 0; + activeslot = 0; + + //Run Loop while the getting is good + while (loop == 1) { + state->dmrburstL = 16; //Use 16 for Voice? + // No CACH in MS Mode? + for(i = 0; i < 12; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cachdata[i] = dibit; + state->dmr_stereo_payload[i] = dibit; + if(i == 2) + { + //state->currentslot = (1 & (dibit >> 1)); + //internalslot = (1 & (dibit >> 1)); + } + } + + //Setup for first AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //First AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+12] = dibit; + redundancyA[i] = dibit; + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //check for repetitive data if caught in a 'no carrier' loop? Just picking random values. + //this will test for no carrier (input signal) and return us to no sync state if necessary + if (redundancyA[16] == redundancyB[16] && redundancyA[27] == redundancyB[27] && + redundancyA[01] == redundancyB[01] && redundancyA[32] == redundancyB[32] && + redundancyA[03] == redundancyB[03] && redundancyA[33] == redundancyB[33] && + redundancyA[13] == redundancyB[13] && redundancyA[07] == redundancyB[07] ) + { + //goto END; + } + for(i = 0; i < 36; i++) + { + redundancyB[i] = redundancyA[i]; + } + + //Setup for Second AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Second AMBE Frame, First Half 18 dibits just before Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+48] = dibit; + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + // signaling data or sync + for(i = 0; i < 24; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+66] = dibit; + syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 + syncdata[(2*i)+1] = (1 & dibit); // bit 0 + sync[i] = (dibit | 1) + 48; + + if (i < 4 || i > 19) // + { + EmbeddedSignalling[2*i] = (1 & (dibit >> 1)); // bit 1 + EmbeddedSignalling[2*i+1] = (1 & dibit); // bit 0 + } + + // load the superframe to do the voiceburstsync processing + if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E + { + /* Time slot 1 superframe buffer filling => SYNC data */ + state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 + state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0 + } + if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E + { + /* Time slot 2 superframe buffer filling => SYNC data */ + state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1 + state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0 + } + + } + + sync[24] = 0; + EmbeddedSignallingOk = -1; + if(QR_16_7_6_decode(EmbeddedSignalling)) + { + EmbeddedSignallingOk = 1; + } + + internalcolorcode = 69; //set so we know if this value is being set properly + if(EmbeddedSignallingOk == 1) + { + state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]); + state->color_code_ok = EmbeddedSignallingOk; + //Power Indicator, not the other PI (header) + state->PI = (unsigned int)EmbeddedSignalling[4]; + state->PI_ok = EmbeddedSignallingOk; + //Link Control Start Stop Indicator + state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); + state->LCSS_ok = EmbeddedSignallingOk; + + } + //else skipcount++; + + //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+90] = dibit; + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + //WIP for RC inbound sync data, part 2, second 24 bits (12 dibits) + if (i <= 12) + { + rcsyncdata[i+12] = (dibit | 1) + 48; //test and double check positions for this sync data + } + + } + + //Setup for Third AMBE Frame + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Third AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+108] = dibit; + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + //end early to allow next sync without skipping a voice superframe + //only use if only doing 6 VC and nothing else, otherwise, will lose sync + if (vc1 == 6 && i == 30) + { + //i = 36; + } + + } + + if ( (strcmp (sync, DMR_MS_VOICE_SYNC) == 0) ) // + { + if (internalslot == 0) + { + vc1 = 1; + fprintf (stderr, "MS Slot 1 Voice Sync \n"); + //activeslot = 0; + + } + if (internalslot == 1) + { + vc2 = 1; + //fprintf (stderr, "MS Slot 2 Voice Sync \n"); + //activeslot = 1; + } + state->dmr_ms_mode = 1; //set to 1 here?? + } + + state->dmr_ms_mode = 1; //set to 1 here? + //testing to see if we need to do something to get MS mode working properly, + //get proper sync, skip frames, etc. + if (state->dmr_ms_mode == 1 ) //&& vc1 < 7 + { + //do something + fprintf (stderr, "MS MODE "); + } + + //don't know if we will catch an RC sync in here or not, should be on VC6 if it occurs + if ( (strcmp (rcsync, DMR_RC_DATA_SYNC) == 0) || (strcmp (sync, DMR_RC_DATA_SYNC) == 0) ) //should be in same position as sync + { + fprintf (stderr,"%s ", getTime()); + if (internalslot == 0) + { + sprintf(state->slot1light, "[slot1]"); + sprintf(state->slot2light, " slot2 "); + fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | RC ", state->color_code); + //test with vc1 reset disabled, if all is well, leave disabled + //vc1 = 1; + } + if (internalslot == 1) + { + sprintf(state->slot2light, "[slot2]"); + sprintf(state->slot1light, " slot1 "); + fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | RC ", state->color_code); + //test with vc1 reset disabled, if all is well, leave disabled + //vc2 = 1; + } + fprintf (stderr, "\n "); //21 spaces to line up the sync + //processDMRdata (opts, state); + state->dmr_ms_rc = 1; //don't know what to do with this, if anything... + goto SKIP; + } + + //check for sync pattern here after collected the rest of the payload, decide what to do with it + if ( (strcmp (sync, DMR_MS_DATA_SYNC) == 0) ) + { + fprintf (stderr,"%s ", getTime()); + if (internalslot == 0) + { + sprintf(state->slot1light, "[slot1]"); + sprintf(state->slot2light, " slot2 "); + //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | MS Data ", state->color_code); + fprintf (stderr,"Sync: +DMR "); + //test with vc1 reset disabled, if all is well, leave disabled + //vc1 = 1; + } + if (internalslot == 1) + { + sprintf(state->slot2light, "[slot2]"); + sprintf(state->slot1light, " slot1 "); + //fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | Data ", state->color_code); + fprintf (stderr,"Sync: +DMR "); + //test with vc1 reset disabled, if all is well, leave disabled + //vc2 = 1; + } + //fprintf (stderr, "\n "); //21 spaces to line up the sync + //fprintf (stderr, " "); //21 spaces to line up the sync + state->dmr_ms_mode = 1; //set to 1 here?? + processDMRdata (opts, state); + skipcount++; + //goto SKIP; + goto END; + } + + if( (strcmp (sync, DMR_MS_DATA_SYNC) != 0) && internalslot == activeslot && vc1 < 7) //only play voice no MS Data Sync and vc1 below 6 (no voice resync) + { + + skipcount = 0; //reset skip count if processing voice frames + fprintf (stderr,"%s ", getTime()); + if (internalslot == 0) + { + fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc1); + } + + if (internalslot == 1) + { + fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | VC%d \n", state->color_code, vc2); + } + if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues) + { + //process voice burst + ProcessVoiceBurstSync(opts, state); + fprintf (stderr, "\n"); + } + if (internalslot == 1 && vc2 == 6) //presumably when full (and no sync issues) + { + //process voice burst + //ProcessVoiceBurstSync(opts, state); + //fprintf (stderr, "\n"); + } + + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + if (internalslot == 0) + { + //vc1++; + } + if (internalslot == 1) + { + vc2++; + } + } + vc1++; + //6 seems optimal for MS, allows to quickly exit and resync if wonky or something + if ( (vc1 > 6) || skipcount > 2) //escape to find new sync if deadspins without a renewed voice frame sync inside of loop + { + goto END; + } + + SKIP: + skipDibit (opts, state, 144); //skip to next slot? + state->dmr_ms_rc = 0; + + //since we are in a repetitive loop, run ncursesPrinter here + if (opts->use_ncurses_terminal == 1) + { + ncursesPrinter(opts, state); + } + + } // end while loop + //reset these variables when exiting MS mode. + END: + //get first half payload dibits and store them in the payload for the next repitition + skipDibit (opts, state, 144); + //CACH + First Half Payload = 12 + 54 + for (i = 0; i < 66; i++) //66 + { + dibit = getDibit(opts, state); + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i] = dibit; + //fprintf(stderr, "%X", state->dmr_stereo_payload[i]); + } + + state->dmr_stereo = 0; + state->dmr_ms_mode = 0; + state->dmr_ms_rc = 0; + +} + +//Only process 2nd half voice payload (3rd frame) and then jump to full MS Voice decoding. +void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) +{ + int i, j, k, l, dibit; + int *dibit_p; + char ambe_fr[4][24] = {0}; + char ambe_fr2[4][24] = {0}; + char ambe_fr3[4][24] = {0}; + const int *w, *x, *y, *z; + char sync[25]; + char syncdata[48]; + char cachdata[13] = {0}; + int mutecurrentslot; + int msMode; + char cc[4]; + unsigned char EmbeddedSignalling[16]; + unsigned int EmbeddedSignallingOk; + + //add time to mirror sync + time_t now; + char * getTime(void) //get pretty hh:mm:ss timestamp + { + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; + } + state->dmrburstL = 16; //Use 16 for Voice? + dibit_p = state->dmr_payload_p - 90; + //payload buffer tests + //CACH + First Half Payload + Sync = 12 + 54 + 24 + //fprintf(stderr, "\n Full DMR Stereo Dump Dibits 90 From Buffer\n"); + for (i = 0; i < 90; i++) //90 + { + state->dmr_stereo_payload[i] = *dibit_p; + dibit_p++; + //fprintf(stderr, "%X", state->dmr_stereo_payload[i]); + } + //end payload buffer test + + for(i = 0; i < 12; i++) + { + dibit = state->dmr_stereo_payload[i]; + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + cachdata[i] = dibit; + } + + //Setup for first AMBE Frame + + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //First AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = state->dmr_stereo_payload[i+12]; + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + //state->dmr_stereo_payload[i+12] = dibit; + ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //Setup for Second AMBE Frame + + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Second AMBE Frame, First Half 18 dibits just before Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = state->dmr_stereo_payload[i+48]; + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling + for(i = 0; i < 18; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr2[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + //Setup for Third AMBE Frame + + //Interleave Schedule + w = rW; + x = rX; + y = rY; + z = rZ; + + //Third AMBE Frame, Full 36 + for(i = 0; i < 36; i++) + { + dibit = getDibit(opts, state); + if(opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr3[*y][*z] = (1 & dibit); // bit 0 + + w++; + x++; + y++; + z++; + + } + + fprintf (stderr, "MS MODE "); + fprintf (stderr,"%s ", getTime()); + fprintf (stderr,"Sync: +DMR | Color Code=XX | DMRSTEREO | VC1 FS \n"); + processMbeFrame (opts, state, NULL, ambe_fr, NULL); + processMbeFrame (opts, state, NULL, ambe_fr2, NULL); + processMbeFrame (opts, state, NULL, ambe_fr3, NULL); + skipDibit (opts, state, 144); //skip to next TDMA slot + dmrMS (opts, state); //bootstrap into full TDMA frame + +} + +void dmrMSData (dsd_opts * opts, dsd_state * state) +{ + int i; + int dibit; + int *dibit_p; + unsigned int burst; + + //add time to mirror sync + time_t now; + char * getTime(void) //get pretty hh:mm:ss timestamp + { + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; + } + + //CACH + First Half Payload + Sync = 12 + 54 + 24 + //fprintf(stderr, "\n Full DMR Stereo Dump Dibits 90 From Buffer\n"); + for (i = 0; i < 90; i++) //90 + { + //fprintf(stderr, "%X", state->dmr_stereo_payload[i]); + } + + for (i = 0; i < 54; i++) + { + dibit = getDibit(opts, state); + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i+90] = dibit; + + } + //fprintf(stderr, "\n"); + //print nice pretty lines + fprintf (stderr, "MS MODE "); + fprintf (stderr, "%s ", getTime()); + //fprintf (stderr, "Sync: +MS DATA | Color Code=XX | DMRSTEREO | Data "); + fprintf (stderr, "Sync: +DMR "); + //fprintf (stderr, "\n "); + + //sprintf for slot 1, doesn't matter, just makes print out of data look uniform setting ahead of time + sprintf(state->slot1light, "[slot1]"); + sprintf(state->slot2light, " slot2 "); + + //process data + state->dmr_stereo = 1; + state->dmr_ms_mode = 1; + processDMRdata (opts, state); + state->dmr_stereo = 0; + state->dmr_ms_mode = 0; + + //get potential first half payload dibits and store them in the payload for the next repitition, MS voice or data. + skipDibit (opts, state, 144); + //CACH + First Half Payload = 12 + 54 + for (i = 0; i < 66; i++) //66 + { + dibit = getDibit(opts, state); + if (opts->inverted_dmr == 1) + { + dibit = (dibit ^ 2); + } + state->dmr_stereo_payload[i] = dibit; + //fprintf(stderr, "%X", state->dmr_stereo_payload[i]); + } + +} diff --git a/src/dmr_process_voice.c b/src/dmr_process_voice.c index da3519f..36bc56d 100644 --- a/src/dmr_process_voice.c +++ b/src/dmr_process_voice.c @@ -19,6 +19,26 @@ #include "dmr_const.h" #include "p25p1_check_hdu.h" // + +// +void ProcessDMR (dsd_opts * opts, dsd_state * state) +{ + uint32_t i, j; + uint32_t Frame; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL; + TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameRC = NULL; //Reverse Test for MS Backwards + + int *errs; + int *errs2; + unsigned long long int k; + int x; + k = 0; + + TSVoiceSupFrameL = &state->TS1SuperFrame; + TSVoiceSupFrameR = &state->TS2SuperFrame; + +// int BP[256] = { 0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903, 0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306, @@ -54,71 +74,53 @@ int BP[256] = { 0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255 }; // -void ProcessDMR (dsd_opts * opts, dsd_state * state) -{ - uint32_t i, j; - uint32_t Frame; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL; - TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL; - - int *errs; - int *errs2; - int *errsR; - int *errs2R; - unsigned long long int k; - int x; - k = 0; - - if(state->currentslot == 0) - { - TSVoiceSupFrame = &state->TS1SuperFrame; - } - else - { - TSVoiceSupFrame = &state->TS2SuperFrame; - } - //TSVoiceSupFrameL = &state->TS1SuperFrame; - //TSVoiceSupFrameR = &state->TS2SuperFrame; - -// -if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) +if (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) { + fprintf (stderr, "%s", KYEL); fprintf(stderr, " BPK %lld", state->K); + fprintf (stderr, "%s", KNRM); + k = BP[state->K]; + k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); for(Frame = 0; Frame < 6; Frame++) { for(i = 0; i < 3; i++) { for(j = 0; j < 49; j++) - { - k = BP[state->K]; - k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); + { x = ( ((k << j) & 0x800000000000) >> 47 ); - TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; - } + TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; + } + } + } +} + +if (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0) +{ + fprintf (stderr, "%s", KYEL); + fprintf(stderr, " BPK %lld", state->K); + fprintf (stderr, "%s", KNRM); + k = BP[state->K]; + k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); + for(Frame = 0; Frame < 6; Frame++) + { + for(i = 0; i < 3; i++) + { + for(j = 0; j < 49; j++) + { + x = ( ((k << j) & 0x800000000000) >> 47 ); + TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; + } } } } // - for(Frame = 0; Frame < 6; Frame++) +if (state->currentslot == 0) +{ + for(Frame = 0; Frame < 6; Frame++) //6 { /* 1 DMR frame contains 3 AMBE voice samples */ - //fprintf (stderr, "\n 1AMBE "); for(i = 0; i < 3; i++) { - - errs = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); - errs2 = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); - state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement - state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement - - mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str, - TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - - /* - if (state->currentslot == 0) - { errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); state->errs = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement @@ -128,45 +130,16 @@ if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - state->debug_audio_errors += *errs2; - //state->debug_audio_errors += *errs2R; - - processAudio(opts, state); - playSynthesizedVoice (opts, state); - } - if (state->currentslot == 1) - { - errsR = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); - errs2R = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); - state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement - state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement - //state->audio_out_temp_bufR = state->audio_out_temp_buf; - - mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errsR, errs2R, state->err_strR, - TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - - state->debug_audio_errors += *errs2R; - processAudio(opts, state); - playSynthesizedVoice (opts, state); - } - - mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, errsR, errs2R, state->err_strR, - TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], - state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); - */ - if (opts->mbe_out_f != NULL) { - saveAmbe2450Data (opts, state, TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); } if (opts->errorbars == 1) { - fprintf(stderr, "%s", state->err_str); + //fprintf(stderr, "%s", state->err_str); } state->debug_audio_errors += *errs2; - //state->debug_audio_errors += *errs2R; processAudio(opts, state); //playSynthesizedVoice (opts, state); @@ -176,14 +149,59 @@ if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) writeSynthesizedVoice (opts, state); } - if (opts->audio_out == 1 && opts->p25enc != 1) //play only if not equal to enc value, going to set p25enc to 1 if enc detected?? + //play only if not equal to enc value, going to set p25enc to 1 if enc detected?? + if (opts->audio_out == 1 && opts->p25enc != 1) { playSynthesizedVoice (opts, state); } } /* End for(i = 0; i < 3; i++) */ } /* End for(Frame = 0; Frame < 6; Frame++) */ -} /* End ProcessDMREncryption() */ - + } //End if Current Slot == 0 + + if (state->currentslot == 1) + { + for(Frame = 0; Frame < 6; Frame++) + { + /* 1 DMR frame contains 3 AMBE voice samples */ + for(i = 0; i < 3; i++) + { + errs = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]); + errs2 = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]); + state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement + state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement + + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str, + TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i], + state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + } + if (opts->errorbars == 1) + { + //fprintf(stderr, "%s", state->err_str); + } + + state->debug_audio_errors += *errs2; + + processAudio(opts, state); + //playSynthesizedVoice (opts, state); + + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } + + //play only if not equal to enc value, going to set p25enc to 1 if enc detected?? + if (opts->audio_out == 1 && opts->p25enc != 1) + { + playSynthesizedVoice (opts, state); + } + } /* End for(i = 0; i < 3; i++) */ + } /* End for(Frame = 0; Frame < 6; Frame++) */ + } //End if Current Slot == 1 +} /* End ProcessDMR */ /* End of file */ diff --git a/src/dmr_sync.c b/src/dmr_sync.c index ade6d1d..0429358 100644 --- a/src/dmr_sync.c +++ b/src/dmr_sync.c @@ -22,6 +22,8 @@ //#define PRINT_TERMINAISON_LC_BYTES //#define PRINT_VOICE_BURST_BYTES +//Need to work in a way to seperate data bursts on seperate slots, having data pouring into both slots simultaneously +//Need to make seperate superframe arrays for each void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]) { //NEED TRELLIS DECODER HERE @@ -36,8 +38,9 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; uint8_t R[3]; uint8_t BPTCReservedBits = 0; + short int slot = 0; - + slot = (short int)state->currentslot; /* Check the current time slot */ if(state->currentslot == 0) { @@ -63,35 +66,46 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] unsigned char tdibits_to_bits[196]; if (1 == 2) { - fprintf (stderr, "\n Raw Trellis Dibits to Bits\n "); + //fprintf (stderr, "\n Raw Trellis Dibits to Bits\n "); for (i = 0; i < 98; i++) { tdibits_to_bits[i * 2] = (tdibits[i] >> 0) & 1; tdibits_to_bits[(i * 2) + 1] = (tdibits[1] >> 1) & 1; - fprintf (stderr, "%d%d", tdibits_to_bits[i * 2], tdibits_to_bits[(i * 2) + 1]); - } - } - if (opts->payload == 1) - { - //fprintf (stderr, "\n Raw Trellis Dibits\n "); - for (i = 0; i < 98; i++) - { - //fprintf (stderr, "#%d [%X] ", i, tdibits[i]); - //tdibits_reverse[97-i] = tdibits[i]; - //tdibits_reverse[97-i] = ((tdibits[i] & 1)<<1) | ((tdibits[i] & 2)>>1); - //tdibits_inverted[i] = tdibits[i] ^ 2; + //fprintf (stderr, "%d%d", tdibits_to_bits[i * 2], tdibits_to_bits[(i * 2) + 1]); } } + //fprintf (stderr, "\n Raw Trellis Dibits\n "); + for (i = 0; i < 98; i++) + { + //fprintf (stderr, "#%d [%X] ", i, tdibits[i]); + tdibits_reverse[97-i] = tdibits[i]; + //tdibits_reverse[97-i] = ((tdibits[i] & 1)<<1) | ((tdibits[i] & 2)>>1); + //tdibits_inverted[i] = tdibits[i] ^ 2; + } + + unsigned char TrellisReturn[18]; - CDMRTrellisDecode(tdibits, TrellisReturn); //figure out how this works!! + //CDMRTrellisDecode(tdibits, TrellisReturn); //figure out how this works!! + CDMRTrellisDecode(tdibits_reverse, TrellisReturn); //NEEDS REVERSE DIBITS! if (opts->payload == 1) { + fprintf (stderr,"%s", KCYN); fprintf (stderr, "\nFull 3/4 Rate Trellis Payload\n "); for (i = 0; i < 18; i++) { fprintf (stderr, "[%02X]", TrellisReturn[i]); } + fprintf (stderr, "\n Hex to Ascii - "); + for (i = 0; i < 18; i++) + { + if (TrellisReturn[i] <= 0x7E && TrellisReturn[i] >=0x20) + { + fprintf (stderr, "%c", TrellisReturn[i]); + } + else fprintf (stderr, "."); + } + fprintf (stderr,"%s", KNRM); //change back to normal } /* Extract the BPTC 196,96 DMR data */ //IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); @@ -100,7 +114,7 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] // /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ //BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); - /* + for(i = 0, j = 0; i < 18; i++, j+=8) { DmrDataBit[j + 0] = (TrellisReturn[i] >> 7) & 0x01; @@ -112,8 +126,9 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] DmrDataBit[j + 6] = (TrellisReturn[i] >> 1) & 0x01; DmrDataBit[j + 7] = (TrellisReturn[i] >> 0) & 0x01; } - */ + //the reverse card + /* for(i = 0, j = 0; i < 18; i++, j+=8) { DmrDataBit[j + 0] = (TrellisReturn[17-i] >> 0) & 0x01; @@ -125,12 +140,14 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] DmrDataBit[j + 6] = (TrellisReturn[17-i] >> 6) & 0x01; DmrDataBit[j + 7] = (TrellisReturn[17-i] >> 7) & 0x01; } + */ /* Convert the 96 bit of voice LC Header data into 12 bytes */ k = 0; - for(i = 0; i < 18; i++) + for(i = 0; i < 16; i++) //16, or 18? seems to have two extra bytes in front currently { - state->dmr_34_rate_sf[i] = state->dmr_34_rate_sf[i+18]; //shift middle to left 12 to load up new round - state->dmr_34_rate_sf[i+18] = state->dmr_34_rate_sf[i+36]; //shift far right to middle 12, going three frames deep; + state->dmr_34_rate_sf[slot][i] = state->dmr_34_rate_sf[slot][i+16]; //shift middle to left 12 to load up new round + state->dmr_34_rate_sf[slot][i+16] = state->dmr_34_rate_sf[slot][i+32]; //shift far right middle to left middle 12, going four frames deep; + state->dmr_34_rate_sf[slot][i+32] = state->dmr_34_rate_sf[slot][i+48]; DmrDataByte[i] = 0; for(j = 0; j < 8; j++) { @@ -139,10 +156,25 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); k++; } - //state->dmr_34_rate_sf[i+36] = DmrDataByte[i]; //copy byte to right hand side of shift frame - state->dmr_34_rate_sf[i+36] = TrellisReturn[i]; + //state->dmr_34_rate_sf[i+36] = ~DmrDataByte[i]; //copy byte to right hand side of shift frame + //state->dmr_34_rate_sf[i+36] = ~TrellisReturn[i]& 0xFF; + state->dmr_34_rate_sf[slot][i+48] = TrellisReturn[i+2]; //plus two to skip the first two bytes } - + if (opts->payload == 2) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n Rate 3/4 Superframe - Slot [%d]\n ",slot+1); + for (i = 0; i < (16*4); i++) + { + fprintf (stderr, "[%02X]", state->dmr_34_rate_sf[slot][i]); + if (i == 15 || i == 31 || i == 47) + { + fprintf (stderr, "\n "); //line break and two spaces after each 16 bytes + } + } + fprintf (stderr, "%s ", KNRM); + } + //fprintf (stderr, "%s ", KNRM); /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ CRCExtracted = 0; //for(i = 0; i < 24; i++) @@ -167,8 +199,9 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] /* Convert corrected 12 bytes into 96 bits */ - //Headers and Addresses + + /* if ( (state->dmr_34_rate_sf[0] & 0x3F) == 0x05) //0x3F?? or == 0x05 { fprintf (stderr, "\n IP4 Header"); @@ -185,27 +218,47 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[5] <<16 ) + (state->dmr_34_rate_sf[6] << 8) + state->dmr_34_rate_sf[7] ); fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[10] << 8) + state->dmr_34_rate_sf[11]); } - //LRRP - if (state->dmr_34_rate_sf[0] == 0x0 && state->dmr_34_rate_sf[4] == 0x0D) //Start LRRP now + */ + //temp hide behind payload until working better + if (opts->payload == 1) { - fprintf (stderr, "\n Data Blocks [%d]", state->dmr_34_rate_sf[5]); - for (short i = 6; i <= 36; i++) + //LRRP + if ( (state->dmr_34_rate_sf[slot][0] & 0x7F) == 0x45) //Start LRRP now + { + //sprintf ( state->dmr_lrrp[state->currentslot][0], "LRRP - "); + fprintf (stderr, "%s ", KMAG); + //fprintf (stderr, "\n IP4 Header"); //Not sure this is accurate info IP4 Header? + //fprintf (stderr, "\n Data Blocks [%d]", state->dmr_34_rate_sf[5]); + for (short i = 1; i < 60; i++) //find way to get padding so we only go as deep as we need to! changed from 64 to 60 to skip the CRC Bytes for confirmed data { - if ( state->dmr_34_rate_sf[i] == 0x34 ) //timestamp + /* + if ( state->dmr_34_rate_sf[slot][i] == 0x0C) //Source and Destination info + { + fprintf (stderr, "\n Source:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[slot][i+0] & 0x3F), state->dmr_34_rate_sf[slot][i+1], state->dmr_34_rate_sf[slot][i+2], state->dmr_34_rate_sf[slot][i+3]); //strip first two bits off 1st byte + fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[slot][i+1] <<16 ) + (state->dmr_34_rate_sf[slot][i+2] << 8) + state->dmr_34_rate_sf[slot][i+3] ); + fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[slot][i+8] << 8) + state->dmr_34_rate_sf[slot][i+9]); + fprintf (stderr, "\n Destination:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[slot][i+4] & 0x3F), state->dmr_34_rate_sf[slot][i+5], state->dmr_34_rate_sf[slot][6], state->dmr_34_rate_sf[slot][i+7]); //strip first two bits off 4th byte?? + fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[slot][i+5] <<16 ) + (state->dmr_34_rate_sf[slot][i+6] << 8) + state->dmr_34_rate_sf[slot][i+7] ); + fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[slot][i+10] << 8) + state->dmr_34_rate_sf[slot][i+11]); + } + */ + if ( state->dmr_34_rate_sf[slot][i] == 0x34 ) //timestamp { fprintf (stderr, "\n LRRP - Timestamp: "); - fprintf (stderr, "%4d.", (state->dmr_34_rate_sf[i+1] << 6) + (state->dmr_34_rate_sf[i+2] >> 2) ); //4 digit year - fprintf (stderr, "%02d.", ( ((state->dmr_34_rate_sf[i+2] & 0x3) << 2) + ((state->dmr_34_rate_sf[i+3] & 0xC0) >> 6)) ); //2 digit month - fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[i+3] & 0x30) >> 1) + ((state->dmr_34_rate_sf[i+3] & 0x0E) >> 1) ); //2 digit day - fprintf (stderr, " %02d:",( (state->dmr_34_rate_sf[i+3] & 0x01) << 4) + ((state->dmr_34_rate_sf[i+4] & 0xF0) >> 4) ); //2 digit hour - fprintf (stderr, "%02d:",( (state->dmr_34_rate_sf[i+4] & 0x0F) << 2) + ((state->dmr_34_rate_sf[i+5] & 0xC0) >> 6) ); //2 digit minute - fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[i+5] & 0x3F) << 0) ); //2 digit second + fprintf (stderr, "%4d.", (state->dmr_34_rate_sf[slot][i+1] << 6) + (state->dmr_34_rate_sf[slot][i+2] >> 2) ); //4 digit year + fprintf (stderr, "%02d.", ( ((state->dmr_34_rate_sf[slot][i+2] & 0x3) << 2) + ((state->dmr_34_rate_sf[slot][i+3] & 0xC0) >> 6)) ); //2 digit month + fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[slot][i+3] & 0x30) >> 1) + ((state->dmr_34_rate_sf[slot][i+3] & 0x0E) >> 1) ); //2 digit day + fprintf (stderr, " %02d:",( (state->dmr_34_rate_sf[slot][i+3] & 0x01) << 4) + ((state->dmr_34_rate_sf[slot][i+4] & 0xF0) >> 4) ); //2 digit hour + fprintf (stderr, "%02d:",( (state->dmr_34_rate_sf[slot][i+4] & 0x0F) << 2) + ((state->dmr_34_rate_sf[slot][i+5] & 0xC0) >> 6) ); //2 digit minute + fprintf (stderr, "%02d", ( (state->dmr_34_rate_sf[slot][i+5] & 0x3F) << 0) ); //2 digit second } - if ( state->dmr_34_rate_sf[i] == 0x51 ) //lattitude and longitude + if ( state->dmr_34_rate_sf[slot][i] == 0x51 ) //lattitude and longitude { fprintf (stderr, "\n LRRP -"); fprintf (stderr, " Lat: "); - if (state->dmr_34_rate_sf[i+1] & 0x80) //first bit indicates a sign, or hemisphere? + if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? { fprintf (stderr, "-"); } @@ -213,47 +266,85 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] long int lrrplon; double lat_unit = (double)180/(double)4294967295; double lon_unit = (double)360/(double)4294967295; - lrrplat = ( ( ((state->dmr_34_rate_sf[i+1] & 0x7F ) << 24 ) + (state->dmr_34_rate_sf[i+2] << 16) + (state->dmr_34_rate_sf[i+3] << 8) + state->dmr_34_rate_sf[i+4]) * 1 ); - lrrplon = ( ( (state->dmr_34_rate_sf[i+5] << 24 ) + (state->dmr_34_rate_sf[i+6] << 16) + (state->dmr_34_rate_sf[i+7] << 8) + state->dmr_34_rate_sf[i+8]) * 1 ); + lrrplat = ( ( ((state->dmr_34_rate_sf[slot][i+1] & 0x7F ) << 24 ) + (state->dmr_34_rate_sf[slot][i+2] << 16) + (state->dmr_34_rate_sf[slot][i+3] << 8) + state->dmr_34_rate_sf[slot][i+4]) * 1 ); + lrrplon = ( ( (state->dmr_34_rate_sf[slot][i+5] << 24 ) + (state->dmr_34_rate_sf[slot][i+6] << 16) + (state->dmr_34_rate_sf[slot][i+7] << 8) + state->dmr_34_rate_sf[slot][i+8]) * 1 ); fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); fprintf (stderr, " Lon: "); - if (state->dmr_34_rate_sf[i+5] & 0x80) //first bit indicates a sign, or hemisphere? + if (state->dmr_34_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? { - fprintf (stderr, "-"); + //fprintf (stderr, "-"); } fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); + if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: -%.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + } + else sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: %.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + //print for easy copy/paste into browser? + //fprintf (stderr, " ("); + if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, " (-%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + //fprintf (stderr, " -"); + } + else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); } - if ( state->dmr_34_rate_sf[i] == 0x6C ) + if ( state->dmr_34_rate_sf[slot][i] == 0x6C ) { //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_34_rate_sf[i+1], state->dmr_34_rate_sf[i+2]); - double velocity = ( ((double)( (state->dmr_34_rate_sf[i+1] ) + state->dmr_34_rate_sf[i+2] )) / ( (double)128)); + double velocity = ( ((double)( (state->dmr_34_rate_sf[slot][i+1] ) + state->dmr_34_rate_sf[slot][i+2] )) / ( (double)128)); //fprintf (stderr, "\n LRRP - %.4lf Meters Per Second", velocity); fprintf (stderr, "\n LRRP - %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); + sprintf ( state->dmr_lrrp[state->currentslot][4], "Vel: %.4lf kph ", (3.6 * velocity)); } - if ( state->dmr_34_rate_sf[i] == 0x56 ) + if ( state->dmr_34_rate_sf[slot][i] == 0x56 ) { //check for appropriate terminology here - Heading, bearing, course, or track? - fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_34_rate_sf[i+1] * 2); + fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_34_rate_sf[slot][i+1] * 2); + sprintf ( state->dmr_lrrp[state->currentslot][5], "Dir: %d Deg ", state->dmr_34_rate_sf[slot][i+1] * 2); } } } + }//end payload + fprintf (stderr, "%s ", KNRM); //Full if (opts->payload == 2) { - fprintf (stderr, "\nFull 3/4 Rate Payload DmrDataByte (reverse bits)\n "); + fprintf (stderr, "\nFull 3/4 Rate Payload DmrDataByte (reverse)\n "); for (i = 0; i < 18; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + + fprintf (stderr, "\nFull 3/4 Rate Payload DmrDataByte (reverse inverted)\n "); + for (i = 0; i < 18; i++) + { + fprintf (stderr, "[%02X]", ~DmrDataByte[i] & 0xFF); + } } } +//This is Data Header, why did I name it Data Data void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { + short int slot = 0; + slot = (short int)state->currentslot; + + //clear out the 3/4 rate data superframe so we don't repeat old info + for (short int i = 0; i < (16*4); i++) + { + state->dmr_34_rate_sf[slot][i] = 0; + } + //clear out the 1/2 rate data superframe so we don't repeat old info + for (short int i = 0; i < (12*3); i++) + { + state->dmr_12_rate_sf[slot][i] = 0; + } + //Placeholder uint32_t i, j, k; uint32_t CRCExtracted = 0; @@ -317,18 +408,18 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint for(i = 0; i < 16; i++) { CRCExtracted = CRCExtracted << 1; - CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); - //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header + //CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1); + CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header } //Look into whether or not we need to run these CRC checks for this header information //and see if its applied the same or differently /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ - CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? - //CRCExtracted = CRCExtracted ^ 0x6969; + //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? + CRCExtracted = CRCExtracted ^ 0xCCCC; /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); + CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xCCCC); //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); /* Convert corrected 12 bytes into 96 bits */ @@ -347,15 +438,16 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint //test if((IrrecoverableErrors == 0) && CRCCorrect) { - fprintf (stderr, "\n(Data CRC Okay)"); + //fprintf (stderr, "\n(Data CRC Okay)"); } else if((IrrecoverableErrors == 0)) { - fprintf (stderr, "\n(Data FEC Okay)"); + //fprintf (stderr, "\n(Data FEC Okay)"); } - else fprintf (stderr, ("\n(Data CRC Fail, FEC Fail)")); + else {}//fprintf (stderr, ("\n(Data CRC Fail, FEC Fail)")); // + fprintf (stderr, "%s ", KMAG); if (DmrDataByte[0] == 0x43) { fprintf (stderr, "\n IP4 Source IP:"); @@ -365,7 +457,12 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[4] & 0x3F), DmrDataByte[5], DmrDataByte[6], DmrDataByte[7]); //not sure if these are right or not fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); } - + if (1 == 1) //already setting by current slot, no need for checking first + { + sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] TGT [%d] ", + ( (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4]), + ( (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7]) ); + } if (DmrDataByte[0] == 0x01) { fprintf (stderr, "\n LRRP Control ACK - "); @@ -374,14 +471,17 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint fprintf (stderr, " Destination:"); fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); } + fprintf (stderr, "%s ", KNRM); //Full if (opts->payload == 1) { - fprintf (stderr, "\nFull Data Rate Payload "); + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\nFull Data Header Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -497,11 +597,13 @@ void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull Rate 1 Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -579,11 +681,11 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint //and see if its applied the same or differently /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? - //CRCExtracted = CRCExtracted ^ 0x6969; + CRCExtracted = CRCExtracted ^ 0xAAAA; /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); - //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xAAAA); /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -617,11 +719,13 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull MBC Header Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -737,11 +841,13 @@ void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull MBC Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -857,11 +963,13 @@ void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull WTF Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -881,6 +989,8 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; uint8_t R[3]; uint8_t BPTCReservedBits = 0; + short int slot = 0; + slot = (short int)state->currentslot; /* Check the current time slot */ if(state->currentslot == 0) @@ -909,8 +1019,10 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ k = 0; for(i = 0; i < 12; i++) { - state->dmr_12_rate_sf[i] = state->dmr_12_rate_sf[i+12]; //shift middle 12 to leftmost 12 to load up new round - state->dmr_12_rate_sf[i+12] = state->dmr_12_rate_sf[i+24]; //shift far right 12 to middle 12, going three frames deep; + state->dmr_12_rate_sf[slot][i] = state->dmr_12_rate_sf[slot][i+12]; //shift middle 12 to leftmost 12 to load up new round + state->dmr_12_rate_sf[slot][i+12] = state->dmr_12_rate_sf[slot][i+24]; //shift middle right 12 to middle left 12, going four frames deep; + state->dmr_12_rate_sf[slot][i+24] = state->dmr_12_rate_sf[slot][i+36]; //shift far right 12 to middle right 12, going four frames deep; + state->dmr_12_rate_sf[slot][i+36] = state->dmr_12_rate_sf[slot][i+48]; DmrDataByte[i] = 0; for(j = 0; j < 8; j++) { @@ -918,7 +1030,22 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); k++; } - state->dmr_12_rate_sf[i+24] = DmrDataByte[i]; //copy byte to right hand side of shift frame + state->dmr_12_rate_sf[slot][i+48] = DmrDataByte[i]; //copy byte to right hand side of shift frame + } + + if (opts->payload == 2) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n Rate 1/2 Superframe - Slot [%d]\n ",slot+1); + for (i = 0; i < (12*5); i++) + { + fprintf (stderr, "[%02X]", state->dmr_12_rate_sf[slot][i]); + if (i == 11 || i == 23 || i == 35 || i == 47) //line break and two spaces after each 16 bytes + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); } /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ @@ -944,13 +1071,18 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ //test if((IrrecoverableErrors == 0) && CRCCorrect) { - fprintf (stderr, "\n(1/2 Rate CRC Okay)"); + //fprintf (stderr, "\n(1/2 Rate CRC Okay)"); } else if((IrrecoverableErrors == 0)) { - fprintf (stderr, "\n(1/2 Rate FEC Okay)"); + //fprintf (stderr, "\n(1/2 Rate FEC Okay)"); + } + else + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, ("\n(1/2 Rate CRC Fail, FEC Fail)")); + fprintf (stderr, "%s", KNRM); } - else fprintf (stderr, ("\n(1/2 Rate CRC Fail, FEC Fail)")); /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -964,45 +1096,42 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; } - - //Headers and Addresses - if ( (state->dmr_12_rate_sf[0] & 0x3F) == 0x05) //0x05, or 0x45? + //Headers Source Destination + //Start Source Destination early in case not enough 1/2 data frames + if ( (state->dmr_12_rate_sf[slot][36] & 0x7F) == 0x45 ) { - fprintf (stderr, "\n IP4 Header"); - } - //ARS? - if ( (state->dmr_12_rate_sf[0] & 0x3F) == 0x0C) - { - fprintf (stderr, "\n Source:"); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[0] & 0x3F), state->dmr_12_rate_sf[1], state->dmr_12_rate_sf[2], state->dmr_12_rate_sf[3]); //strip first two bits off 1st byte - fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[1] <<16 ) + (state->dmr_12_rate_sf[2] << 8) + state->dmr_12_rate_sf[3] ); - fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[8] << 8) + state->dmr_12_rate_sf[9]); - fprintf (stderr, "\n Destination:"); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[4] & 0x3F), state->dmr_12_rate_sf[5], state->dmr_12_rate_sf[6], state->dmr_12_rate_sf[7]); //strip first two bits off 4th byte?? - fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[5] <<16 ) + (state->dmr_12_rate_sf[6] << 8) + state->dmr_12_rate_sf[7] ); - fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[10] << 8) + state->dmr_12_rate_sf[11]); - } - //LRRP - if (state->dmr_12_rate_sf[0] == 0x0 && state->dmr_12_rate_sf[4] == 0x0D) //Start LRRP now - { - //fprintf (stderr, "\n Data Blocks [%d]", state->dmr_12_rate_sf[5]); - for (short i = 6; i <= 36; i++) + fprintf (stderr, "%s ", KMAG); + //fprintf (stderr, "\n IP4 Header"); //Not sure this is accurate info IP4 Header? + //fprintf (stderr, "\n Data Blocks [%d]", state->dmr_34_rate_sf[5]); + for (short i = 36; i < 60; i++) //find way to get padding so we only go as deep as we need to! { - if ( state->dmr_12_rate_sf[i] == 0x34 ) //timestamp + if ( state->dmr_12_rate_sf[slot][i] == 0x0C) //Source and Destination info { - fprintf (stderr, "\n LRRP - Timestamp: "); - fprintf (stderr, "%4d.", (state->dmr_12_rate_sf[i+1] << 6) + (state->dmr_12_rate_sf[i+2] >> 2) ); //4 digit year - fprintf (stderr, "%02d.", ( ((state->dmr_12_rate_sf[i+2] & 0x3) << 2) + ((state->dmr_12_rate_sf[i+3] & 0xC0) >> 6)) ); //2 digit month - fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[i+3] & 0x30) >> 1) + ((state->dmr_12_rate_sf[i+3] & 0x0E) >> 1) ); //2 digit day - fprintf (stderr, " %02d:",( (state->dmr_12_rate_sf[i+3] & 0x01) << 4) + ((state->dmr_12_rate_sf[i+4] & 0xF0) >> 4) ); //2 digit hour - fprintf (stderr, "%02d:",( (state->dmr_12_rate_sf[i+4] & 0x0F) << 2) + ((state->dmr_12_rate_sf[i+5] & 0xC0) >> 6) ); //2 digit minute - fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[i+5] & 0x3F) << 0) ); //2 digit second + fprintf (stderr, "\n Source:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+0] & 0x3F), state->dmr_12_rate_sf[slot][i+1], state->dmr_12_rate_sf[slot][i+2], state->dmr_12_rate_sf[slot][i+3]); //strip first two bits off 1st byte + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+1] <<16 ) + (state->dmr_12_rate_sf[slot][i+2] << 8) + state->dmr_12_rate_sf[slot][i+3] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[slot][i+8] << 8) + state->dmr_12_rate_sf[slot][i+9]); + fprintf (stderr, "\n Destination:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+4] & 0x3F), state->dmr_12_rate_sf[slot][i+5], state->dmr_12_rate_sf[slot][6], state->dmr_12_rate_sf[slot][i+7]); //strip first two bits off 4th byte?? + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+5] <<16 ) + (state->dmr_12_rate_sf[slot][i+6] << 8) + state->dmr_12_rate_sf[slot][i+7] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[slot][i+10] << 8) + state->dmr_12_rate_sf[slot][i+11]); } - if ( state->dmr_12_rate_sf[i] == 0x51 ) //lattitude and longitude + } + fprintf (stderr, "%s ", KNRM); + } + /* + //Jurek lrrp, 0x41 is probably a different header type or something, or I need to look at the data header packet PDU first. + if ( (state->dmr_12_rate_sf[slot][36] & 0x7F) == 0x41) //Start LRRP now + { + sprintf ( state->dmr_lrrp[state->currentslot][0], "LRRP - "); + fprintf (stderr, "%s ", KMAG); + for (short i = 36; i < 60; i++) //find way to get padding so we only go as deep as we need to! + { + if ( state->dmr_12_rate_sf[slot][i] == 0x51 ) //lattitude and longitude { fprintf (stderr, "\n LRRP -"); fprintf (stderr, " Lat: "); - if (state->dmr_12_rate_sf[i+1] & 0x80) //first bit indicates a sign, or hemisphere? + if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? { fprintf (stderr, "-"); } @@ -1010,46 +1139,150 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ long int lrrplon; double lat_unit = (double)180/(double)4294967295; double lon_unit = (double)360/(double)4294967295; - lrrplat = ( ( ((state->dmr_12_rate_sf[i+1] & 0x7F ) << 24 ) + (state->dmr_12_rate_sf[i+2] << 16) + (state->dmr_12_rate_sf[i+3] << 8) + state->dmr_12_rate_sf[i+4]) * 1 ); - lrrplon = ( ( (state->dmr_12_rate_sf[i+5] << 24 ) + (state->dmr_12_rate_sf[i+6] << 16) + (state->dmr_12_rate_sf[i+7] << 8) + state->dmr_12_rate_sf[i+8]) * 1 ); + lrrplat = ( ( ((state->dmr_12_rate_sf[slot][i+1] & 0x7F ) << 24 ) + (state->dmr_12_rate_sf[slot][i+2] << 16) + (state->dmr_12_rate_sf[slot][i+3] << 8) + state->dmr_12_rate_sf[slot][i+4]) * 1 ); + lrrplon = ( ( (state->dmr_12_rate_sf[slot][i+5] << 24 ) + (state->dmr_12_rate_sf[slot][i+6] << 16) + (state->dmr_12_rate_sf[slot][i+7] << 8) + state->dmr_12_rate_sf[slot][i+8]) * 1 ); fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); fprintf (stderr, " Lon: "); - if (state->dmr_12_rate_sf[i+5] & 0x80) //first bit indicates a sign, or hemisphere? + if (state->dmr_12_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? { //fprintf (stderr, "-"); } fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); - //sprintf ( state->dmr_lrrp[3], "Lat: %.5lf Lon: %.5lf", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: %.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + //print for easy copy/paste into browser? + //fprintf (stderr, " ("); + if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + } + fprintf (stderr, "%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); } - if ( state->dmr_12_rate_sf[i] == 0x6C ) + if ( state->dmr_12_rate_sf[slot][i] == 0x6C ) { //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. - //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_12_rate_sf[i+1], state->dmr_12_rate_sf[i+2]); - double velocity = ( ((double)( (state->dmr_12_rate_sf[i+1] ) + state->dmr_12_rate_sf[i+2] )) / ( (double)128)); + //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_34_rate_sf[i+1], state->dmr_34_rate_sf[i+2]); + double velocity = ( ((double)( (state->dmr_12_rate_sf[slot][i+1] ) + state->dmr_12_rate_sf[slot][i+2] )) / ( (double)128)); //fprintf (stderr, "\n LRRP - %.4lf Meters Per Second", velocity); fprintf (stderr, "\n LRRP - %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); - //sprintf ( state->dmr_lrrp[1], "Vel: %.4lf kph", (3.6 * velocity)); + sprintf ( state->dmr_lrrp[state->currentslot][4], "Vel: %.4lf kph ", (3.6 * velocity)); } - if ( state->dmr_12_rate_sf[i] == 0x56 ) + if ( state->dmr_12_rate_sf[slot][i] == 0x56 ) { //check for appropriate terminology here - Heading, bearing, course, or track? - fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_12_rate_sf[i+1] * 2); - //sprintf ( state->dmr_lrrp[2], "Dir: %d Deg", state->dmr_12_rate_sf[i+1] * 2); + fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_12_rate_sf[slot][i+1] * 2); + sprintf ( state->dmr_lrrp[state->currentslot][5], "Dir: %d Deg ", state->dmr_12_rate_sf[slot][i+1] * 2); } } } + //end Jurek lrrp + */ + //LRRP + if ( (state->dmr_12_rate_sf[slot][0] & 0x7F) == 0x45) //Start LRRP now + { + //sprintf ( state->dmr_lrrp[state->currentslot][0], "LRRP - "); + fprintf (stderr, "%s ", KMAG); + //fprintf (stderr, "\n IP4 Header"); //Not sure this is accurate info IP4 Header? + //fprintf (stderr, "\n Data Blocks [%d]", state->dmr_34_rate_sf[5]); + for (short i = 1; i < 56; i++) //find way to get padding so we only go as deep as we need to! changed from 60 to 56 to skip the CRC bytes + { + /* + if ( state->dmr_12_rate_sf[slot][i] == 0x0C) //Source and Destination info + { + fprintf (stderr, "\n Source:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+0] & 0x3F), state->dmr_12_rate_sf[slot][i+1], state->dmr_12_rate_sf[slot][i+2], state->dmr_12_rate_sf[slot][i+3]); //strip first two bits off 1st byte + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+1] <<16 ) + (state->dmr_12_rate_sf[slot][i+2] << 8) + state->dmr_12_rate_sf[slot][i+3] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[slot][i+8] << 8) + state->dmr_12_rate_sf[slot][i+9]); + fprintf (stderr, "\n Destination:"); + fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_12_rate_sf[slot][i+4] & 0x3F), state->dmr_12_rate_sf[slot][i+5], state->dmr_12_rate_sf[slot][6], state->dmr_12_rate_sf[slot][i+7]); //strip first two bits off 4th byte?? + fprintf (stderr, " [%08d]", (state->dmr_12_rate_sf[slot][i+5] <<16 ) + (state->dmr_12_rate_sf[slot][i+6] << 8) + state->dmr_12_rate_sf[slot][i+7] ); + fprintf (stderr, " - Port %05d", (state->dmr_12_rate_sf[slot][i+10] << 8) + state->dmr_12_rate_sf[slot][i+11]); + } + */ + if ( state->dmr_12_rate_sf[slot][i] == 0x34 ) //timestamp + { + fprintf (stderr, "\n LRRP - Timestamp: "); + fprintf (stderr, "%4d.", (state->dmr_12_rate_sf[slot][i+1] << 6) + (state->dmr_12_rate_sf[slot][i+2] >> 2) ); //4 digit year + fprintf (stderr, "%02d.", ( ((state->dmr_12_rate_sf[slot][i+2] & 0x3) << 2) + ((state->dmr_12_rate_sf[slot][i+3] & 0xC0) >> 6)) ); //2 digit month + fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[slot][i+3] & 0x30) >> 1) + ((state->dmr_12_rate_sf[slot][i+3] & 0x0E) >> 1) ); //2 digit day + fprintf (stderr, " %02d:",( (state->dmr_12_rate_sf[slot][i+3] & 0x01) << 4) + ((state->dmr_12_rate_sf[slot][i+4] & 0xF0) >> 4) ); //2 digit hour + fprintf (stderr, "%02d:",( (state->dmr_12_rate_sf[slot][i+4] & 0x0F) << 2) + ((state->dmr_12_rate_sf[slot][i+5] & 0xC0) >> 6) ); //2 digit minute + fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[slot][i+5] & 0x3F) << 0) ); //2 digit second + } + if ( state->dmr_12_rate_sf[slot][i] == 0x51 ) //lattitude and longitude + { + fprintf (stderr, "\n LRRP -"); + fprintf (stderr, " Lat: "); + if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + } + long int lrrplat; + long int lrrplon; + double lat_unit = (double)180/(double)4294967295; + double lon_unit = (double)360/(double)4294967295; + lrrplat = ( ( ((state->dmr_12_rate_sf[slot][i+1] & 0x7F ) << 24 ) + (state->dmr_12_rate_sf[slot][i+2] << 16) + (state->dmr_12_rate_sf[slot][i+3] << 8) + state->dmr_12_rate_sf[slot][i+4]) * 1 ); + lrrplon = ( ( (state->dmr_12_rate_sf[slot][i+5] << 24 ) + (state->dmr_12_rate_sf[slot][i+6] << 16) + (state->dmr_12_rate_sf[slot][i+7] << 8) + state->dmr_12_rate_sf[slot][i+8]) * 1 ); + fprintf (stderr, "%.5lf ", ((double)lrrplat) * lat_unit); + fprintf (stderr, " Lon: "); + if (state->dmr_12_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? + { + //fprintf (stderr, "-"); + } + fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); + if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: -%.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + } + else sprintf ( state->dmr_lrrp[state->currentslot][3], "Lat: %.5lf Lon: %.5lf ", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); //print for easy copy/paste into browser? + //fprintf (stderr, " ("); + if (state->dmr_12_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, " (-%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + } + else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + } + if ( state->dmr_12_rate_sf[slot][i] == 0x6C ) + { + //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. + //fprintf (stderr, "\n LRRP - Vi %02X Vf %02X Velocity Units (hex)", state->dmr_34_rate_sf[i+1], state->dmr_34_rate_sf[i+2]); + double velocity = ( ((double)( (state->dmr_12_rate_sf[slot][i+1] ) + state->dmr_12_rate_sf[slot][i+2] )) / ( (double)128)); + //fprintf (stderr, "\n LRRP - %.4lf Meters Per Second", velocity); + fprintf (stderr, "\n LRRP - %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity) ); + sprintf ( state->dmr_lrrp[state->currentslot][4], "Vel: %.4lf kph ", (3.6 * velocity)); + } + if ( state->dmr_12_rate_sf[slot][i] == 0x56 ) + { + //check for appropriate terminology here - Heading, bearing, course, or track? + fprintf (stderr, "\n LRRP - Direction %d Degrees", state->dmr_12_rate_sf[slot][i+1] * 2); + sprintf ( state->dmr_lrrp[state->currentslot][5], "Dir: %d Deg ", state->dmr_12_rate_sf[slot][i+1] * 2); + } + } + } + fprintf (stderr, "%s ", KNRM); + //Full if (opts->payload == 1) { - fprintf (stderr, "\nFull 1/2 Rate Payload "); + fprintf (stderr,"%s", KCYN); + fprintf (stderr, "\n Full 1/2 Rate Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "\n Hex to Ascii - "); + for (i = 0; i < 12; i++) + { + if (DmrDataByte[i] <= 0x7E && DmrDataByte[i] >=0x20) + { + fprintf (stderr, "%c", DmrDataByte[i]); + } + else fprintf (stderr, "."); + } + fprintf (stderr,"%s", KNRM); } } @@ -1127,22 +1360,27 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t //and see if its applied the same or differently /* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */ //CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI? - CRCExtracted = CRCExtracted ^ 0x6969; + CRCExtracted = CRCExtracted ^ 0xA5A5; /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696); - CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); + CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xA5A5); //test if((IrrecoverableErrors == 0) && CRCCorrect) { - fprintf (stderr, "\n(CSBK CRC Okay)"); + //fprintf (stderr, "\n(CSBK CRC Okay)"); } else if((IrrecoverableErrors == 0)) { - fprintf (stderr, "\n(CSBK FEC Okay)"); + //fprintf (stderr, "\n(CSBK FEC Okay)"); + } + else + { + //fprintf (stderr, "%s", KRED); + //fprintf (stderr, ("\n(CSBK CRC Fail, FEC Fail)")); + //fprintf (stderr, "%s", KNRM); } - else fprintf (stderr, ("\n(CSBK CRC Fail, FEC Fail)")); /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -1170,8 +1408,10 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t uint8_t nb3 = DmrDataByte[4] & 0x3F; //extract(csbk, 34, 40); uint8_t nb4 = DmrDataByte[5] & 0x3F; //extract(csbk, 42, 48); uint8_t nb5 = DmrDataByte[6] & 0x3F; //extract(csbk, 50, 56); + fprintf (stderr, "%s", KMAG); fprintf (stderr, "\nMotoTRBO Connect Plus Neighbors\n"); fprintf(stderr, " NB1(%02x), NB2(%02x), NB3(%02x), NB4(%02x), NB5(%02x)", nb1, nb2, nb3, nb4, nb5); + fprintf (stderr, "%s", KNRM); sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); } //ConnectPLUS Section // @@ -1181,8 +1421,10 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "%s", KGRN); fprintf (stderr, "\nMotoTRBO Connect Plus Channel Grant\n"); fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + fprintf (stderr, "%s", KNRM); sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); } @@ -1192,8 +1434,10 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "%s", KRED); fprintf (stderr, "\nMotoTRBO Connect Plus Terminate Channel Grant\n"); //Data only shows a srcAddr?? fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + fprintf (stderr, "%s", KNRM); sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); } @@ -1203,8 +1447,10 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t uint32_t grpAddr = ( (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); //extract(csbk, 40, 64); uint8_t lcn = ( (DmrDataByte[8] & 0xF0 ) >> 4 ) ; //extract(csbk, 64, 68); 0xF0 LCN not report same as 'plus'? uint8_t tslot = ( (DmrDataByte[8] & 0x08 ) >> 3 ); //csbk[68]; TS seems fine + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nMotoTRBO Connect Plus Data Channel Grant\n"); //Data I have doesn't show any values for lcn or tslot fprintf(stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot); + fprintf (stderr, "%s", KNRM); sprintf(state->dmr_branding, " MotoTRBO Connect Plus "); } @@ -1292,7 +1538,7 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t //possible Site identifier, CSBK Aloha? if (csbk_o == 0x19) //DmrDataByte[0] == 0x99? { - fprintf (stderr, "\n CSBK Aloha?"); + //fprintf (stderr, "\n CSBK Aloha?"); //fprintf (stderr, "\n Site ID %d-%d.%d", (DmrDataByte[2] & 0xF0 >> 4), DmrDataByte[2] & 0xF, DmrDataByte[3]); //fprintf (stderr, " DCC %d", DmrDataByte[1]); //sprintf ( state->dmr_callsign[0], "Site ID %d-%d.%d", (DmrDataByte[2] & 0xF0 >> 4), DmrDataByte[2] & 0xF, DmrDataByte[3]); @@ -1330,11 +1576,13 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull CSBK Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } } @@ -1428,25 +1676,61 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; } - - state->payload_algid = DmrDataByte[0]; - state->payload_keyid = DmrDataByte[2]; - state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); - if (1 == 1) //have it always print? + if (state->currentslot == 0) { - fprintf (stderr, "\n DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi); + state->payload_algid = DmrDataByte[0]; + state->payload_keyid = DmrDataByte[2]; + state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); + if (1 == 1) //have it always print? + { + fprintf (stderr, "%s ", KYEL); + fprintf (stderr, "\n Slot 1"); + fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi); + fprintf (stderr, "%s ", KNRM); + } } + if (state->currentslot == 1) + { + state->payload_algidR = DmrDataByte[0]; + state->payload_keyidR = DmrDataByte[2]; + state->payload_miR = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); + if (1 == 1) //have it always print? + { + fprintf (stderr, "%s ", KYEL); + fprintf (stderr, "\n Slot 2"); + fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR); + fprintf (stderr, "%s ", KNRM); + } + } + + //test if((IrrecoverableErrors == 0) && CRCCorrect) { - fprintf (stderr, " (PI CRC Okay)"); + //fprintf (stderr, " (PI CRC Okay)"); } else if((IrrecoverableErrors == 0)) { - fprintf (stderr, " (PI FEC Okay)"); + //fprintf (stderr, " (PI FEC Okay)"); + } + else { + fprintf (stderr, "%s ", KRED); + fprintf (stderr, (" (PI CRC Fail, FEC Fail)")); + fprintf (stderr, "%s ", KNRM); + } + + //Full + if (opts->payload == 1) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\nFull PI Header Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + fprintf (stderr, "%s", KNRM); } - else fprintf (stderr, (" (PI CRC Fail, FEC Fail)")); } @@ -1575,6 +1859,7 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 } } /* Print the destination ID (TG) and the source ID */ + fprintf (stderr, "%s ", KGRN); fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; @@ -1591,13 +1876,16 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 * a PI Header will be sent with the encryption mode and DSD will upgrade automatically * the new encryption mode */ opts->EncryptionMode = MODE_BASIC_PRIVACY; - + fprintf (stderr, "%s ", KRED); fprintf(stderr, "Encrypted "); + //fprintf (stderr, "%s ", KNRM); } else { opts->EncryptionMode = MODE_UNENCRYPTED; + fprintf (stderr, "%s ", KGRN); fprintf(stderr, "Clear/Unencrypted "); + //fprintf (stderr, "%s ", KNRM); } /* Check the "Reserved" bits */ @@ -1618,10 +1906,11 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 else fprintf(stderr, "No Priority "); /* We should never go here */ } fprintf(stderr, "Call "); + fprintf (stderr, "%s ", KNRM); - if(TSVoiceSupFrame->FullLC.DataValidity) fprintf(stderr, "(CRC OK ) "); - else if(IrrecoverableErrors == 0) fprintf(stderr, "RAS (FEC OK/CRC ERR)"); - else fprintf(stderr, "(FEC FAIL/CRC ERR)"); + if(TSVoiceSupFrame->FullLC.DataValidity) {}//fprintf(stderr, "(CRC OK ) "); + else if(IrrecoverableErrors == 0) {}//fprintf(stderr, "RAS (FEC OK/CRC ERR)"); + else {}//fprintf(stderr, "(FEC FAIL/CRC ERR)"); #ifdef PRINT_VOICE_LC_HEADER_BYTES fprintf(stderr, "\n"); @@ -1657,12 +1946,15 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 //Full if (opts->payload == 1) { - fprintf (stderr, "\nFull Voice Header Payload "); + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\nFull Voice LC Header Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } + fprintf (stderr, "%s", KNRM); } + } /* End ProcessDmrVoiceLcHeader() */ @@ -1797,9 +2089,12 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 //tlc if((IrrecoverableErrors == 0) && CRCCorrect) //amateur DMR seems to only set radio ID up here I think, figure out best way to set without messing up other DMR types { - fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf (stderr, "%s \n", KRED); + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - fprintf(stderr, "(CRC OK ) "); + fprintf (stderr, "%s ", KNRM); + //fprintf(stderr, "(CRC OK ) "); if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0) //other opcodes may convey callsigns, names, etc. /* if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || @@ -1809,11 +2104,24 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever */ { - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_color_code = state->color_code; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + if (state->currentslot == 0) + { + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + //state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } + + } //only set on good CRC value or corrected values //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; @@ -1824,9 +2132,12 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 } else if(IrrecoverableErrors == 0) { - fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf (stderr, "%s \n", KRED); + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); fprintf(stderr, "RAS (FEC OK/CRC ERR)"); //tlc + fprintf (stderr, "%s ", KNRM); if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0) //other opcodes may convey callsigns, names, etc. /* if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || @@ -1836,11 +2147,22 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever */ { - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_color_code = state->color_code; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + if (state->currentslot == 0) + { + //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + //state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; + //state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } } //only set on good CRC value or corrected values //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; @@ -1849,7 +2171,7 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; //state->dmr_color_code = state->color_code; } - else fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); + else {} //fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); #ifdef PRINT_TERMINAISON_LC_BYTES fprintf(stderr, "\n"); @@ -1881,6 +2203,17 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors); #endif /* PRINT_TERMINAISON_LC_BYTES */ + + if (opts->payload == 1) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\nFull TLC Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + fprintf (stderr, "%s", KNRM); + } } /* End ProcessDmrTerminaisonLC() */ @@ -1993,7 +2326,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) /* Check the CRC values */ if((IrrecoverableErrors == 0))// && CRCCorrect) { - /* Data ara correct */ + /* Data is correct */ //fprintf(stderr, "\nLink Control (LC) Data CRCs are correct !!! Number of error = %u\n", NbOfError); /* CRC is correct so consider the Full LC data as correct/valid */ @@ -2005,94 +2338,106 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) TSVoiceSupFrame->FullLC.DataValidity = 0; } - //GPS, not sure if in right place or not though - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0x08) - { - long int lrrplat; - long int lrrplon; - double lat_unit = (double)180/(double)4294967295; //damned floats screweing me over lol - double lon_unit = (double)360/(double)4294967295; - //lrrplat = ( ( ((DmrDataByte[0] & 0x3F) << 24 ) + (DmrDataByte[1] << 16) + (DmrDataByte[2] << 8) + DmrDataByte[3]) * 1 ); //(0x0B4/0xFFFFFFFF) - //lrrplon = ( ( (DmrDataByte[4] << 24 ) + (DmrDataByte[5] << 16) + (DmrDataByte[6] << 8) + DmrDataByte[7]) * 1 ); //(0x168/0xFFFFFFFF) //0x3F, or whole thing?; - - //fprintf (stderr, " Standard GPS Coordinates?? Check Payload.\n"); - //fprintf (stderr, "Figure out what to put here"); - - } - //ASCII HEX cheat sheet // 20 - space; 09 - Horizontal Tab; 0A Line Feed; 0D - Carriage Feed; 00 - Null; // 30 - 39 are 0-9 numerals // 41 - 5A are upper case A-Z letters // 61-7A are lower case a-z letters - // + // 7B-7F misc characters (colon, semicolon, etc) // let's assume that something has to indicate end of valid characters? - if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x03 && TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x08 && opts->payload == 1) + + //Embedded Alias + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x03 && TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x08) { - //fprintf (stderr, "Call Sign %X [ ", TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3); - sprintf (state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], ""); //blank here so it doesn't grow out of control? + sprintf (state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], ""); //blank here so it doesn't grow out of control? for (i = 0; i < 10; i++) { - if ( - //(LC_DataBytes[i] > 0x29 && LC_DataBytes[i] < 0x3A) || //numerals - //(LC_DataBytes[i] > 0x40 && LC_DataBytes[i] < 0x5B) || //uppers - //(LC_DataBytes[i] > 0x60 && LC_DataBytes[i] < 0x7B) || //lowers - //(LC_DataBytes[i] == 0x20) ) //space - (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) //full range of 'normal' characters? + //full range of alphanumerical characters? + if ( (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) { - //fprintf (stderr, "%c", LC_DataBytes[i]); - sprintf ( state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + - strlen(state->dmr_callsign[TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); + sprintf ( state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + + strlen(state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); } } - //fprintf (stderr, "]\n"); if (opts->use_ncurses_terminal == 1) { - fprintf (stderr, "\n Alias Header and Blocks: [%s%s%s%s%s]", state->dmr_callsign[0], state->dmr_callsign[1], state->dmr_callsign[2], state->dmr_callsign[3], state->dmr_callsign[4] ); + fprintf (stderr, "%s", KMAG); + if (state->dmr_stereo == 0) + { + fprintf(stderr, "\n"); + } + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf (stderr, " Embedded Alias Header and Blocks: [%s%s%s%s%s]", state->dmr_callsign[state->currentslot][0], + state->dmr_callsign[state->currentslot][1], state->dmr_callsign[state->currentslot][2], + state->dmr_callsign[state->currentslot][3], state->dmr_callsign[state->currentslot][4] ); + fprintf (stderr, "%s ", KNRM); + } + } + + if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode == 0x08 && opts->payload == 1) //Embedded GPS + { + sprintf (state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3], ""); //blank here so it doesn't grow out of control? + for (i = 0; i < 10; i++) + { + //full range of alphanumerical characters? + if ( (LC_DataBytes[i] > 0x19 && LC_DataBytes[i] < 0x7F) ) + { + sprintf ( state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3] + + strlen(state->dmr_callsign[state->currentslot][TSVoiceSupFrame->FullLC.FullLinkControlOpcode - 3]) , "%c", LC_DataBytes[i]); + } + } + if (opts->use_ncurses_terminal == 1) + { + fprintf (stderr, "%s", KCYN); + if (state->dmr_stereo == 0) + { + fprintf(stderr, "\n"); + } + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf (stderr, " Embedded GPS: [%s]", state->dmr_callsign[state->currentslot][5] ); + fprintf (stderr, "%s ", KNRM); } } /* Print the destination ID (TG) and the source ID */ - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x09) //voice burst, was > 0x07 + if((IrrecoverableErrors == 0) && CRCCorrect) { - //fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - } - - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - - if((IrrecoverableErrors == 0) && CRCCorrect) //voice burst - { - //fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - //fprintf(stderr, "(CRC OK ) "); - //only set on good CRC? - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x09) //other opcodes may convey callsigns, names, etc. was > 0x07 - /* - if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //work out why amateur sets sourceid on other codes, but pro only does on whatever - */ + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x08) //other opcodes may convey callsigns, names, etc. was > 0x07 { - fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf (stderr, "%s", KGRN); + if (state->dmr_stereo == 0) + { + fprintf(stderr, "\n"); + } + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - fprintf(stderr, "(CRC OK ) "); - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_color_code = state->color_code; + fprintf (stderr, "%s ", KNRM); + //fprintf(stderr, "(CRC OK ) "); + if (state->currentslot == 0) + { + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } + //state->dmr_color_code = state->color_code; //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; } //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; //state->dmr_color_code = state->color_code; } else if(IrrecoverableErrors == 0) @@ -2101,31 +2446,46 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); //fprintf(stderr, "RAS (FEC OK/CRC ERR)"); //voice burst //or set if was corrected - if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x07) //other opcodes may convey callsigns, names, etc. - /* - if ( TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0xAF || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x04 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x05 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x06 || - TSVoiceSupFrame->FullLC.FullLinkControlOpcode != 0x07 ) //other opcodes may convey callsigns, names, etc. - */ + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x08) //7, or 8? { - fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); + fprintf (stderr, "%s", KGRN); + if (state->dmr_stereo == 0) + { + fprintf(stderr, "\n"); + } + fprintf (stderr, " SLOT %d", state->currentslot+1); + fprintf(stderr, " TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); + fprintf (stderr, "%s ", KRED); fprintf(stderr, "RAS (FEC OK/CRC ERR) "); - state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; - state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_color_code = state->color_code; + fprintf (stderr, "%s ", KNRM); + if (state->currentslot == 0) + { + state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + state->lasttgR = TSVoiceSupFrame->FullLC.GroupAddress; + state->lastsrcR = TSVoiceSupFrame->FullLC.SourceAddress; + //state->dmr_color_code = state->color_code; + state->dmr_fidR = TSVoiceSupFrame->FullLC.FeatureSetID; + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } + //state->dmr_color_code = state->color_code; //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; } //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; + //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; //state->dmr_color_code = state->color_code; } - else fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); + else {} //fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); #ifdef PRINT_VOICE_BURST_BYTES //fprintf(stderr, "\n"); @@ -2159,13 +2519,16 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) //Full if (opts->payload == 1) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "\nFull Voice Burst Payload "); //for (i = 0; i < 8; i++) for (i = 0; i < 10; i++) { fprintf (stderr, "[%02X]", LC_DataBytes[i]); //amateur DMR hams seem to use this area to send callsigns and names using 04,05,06,07 opcodes } - //fprintf (stderr, "\n"); + fprintf (stderr, "%s", KNRM); + + } } /* End ProcessVoiceBurstSync() */ diff --git a/src/dmr_voice.c b/src/dmr_voice.c index a25e9ff..e7322c3 100644 --- a/src/dmr_voice.c +++ b/src/dmr_voice.c @@ -115,10 +115,29 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) state->slot1light[0] = ' '; state->slot1light[6] = ' '; } + //method to only listen to a chosen slot when voices occupy both slots simultaneously + //method supersceeded by DMRSTEREO + //state->hardslot = 9; //0 to only listen to slot 0 voice, 1 for slot 1, 9 for both + //if(state->hardslot != 9 && state->hardslot != state->currentslot) + //if(1==1) + //{ + //fprintf (stderr, " Current Slot = %d", state->currentslot + 1); + //fprintf (stderr, "\n"); //line break after breaking out of jail + //goto JUMP; + //} } } cachdata[12] = 0; + //set state-dmrburstL and R here to a value for ncurses + if (state->currentslot == 0) + { + state->dmrburstL = 16; //use 16 for Voice? + } + if (state->currentslot == 1) + { + state->dmrburstR = 16; //Use 16 for Voice? + } #ifdef DMR_DUMP k = 0; @@ -370,10 +389,23 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) sprintf(state->slot2light, "[sLoT2]"); } - if((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) + //Comment out Below Lines, or switch if/else if if these cause issues. + /* + else if((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0)) { msMode = 1; + if strcmp (sync, DMR_MS_VOICE_SYNC) == 0) + { + //quickDMRVoice (opts, state); //or make handler for msvoice seperate + //goto JUMP; //quit early when returned here + } } + else if((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) + { + //quickDMRVoice (opts, state); //or make handler for msvoice seperate + //goto JUMP; //quit early when returned here + } + */ // TODO : To be removed // if((j == 0) && (opts->errorbars == 1)) @@ -574,8 +606,9 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) fprintf(stderr, "%s ", syncbits); #endif - if(j == 5) + if(j == 5) //j == 5 { + // 2nd half next slot skipDibit (opts, state, 54); @@ -617,6 +650,7 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) } } + } /* End for(j = 0; j < 6; j++) */ if(opts->errorbars == 1) @@ -624,14 +658,25 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) fprintf(stderr, "%s %s ", state->slot1light, state->slot2light); /* Print the color code */ + fprintf (stderr, "%s", KCYN); fprintf(stderr, "| Color Code=%02d ", (int)state->color_code); + fprintf (stderr, "%s", KNRM); //if(state->color_code_ok) fprintf(stderr, "(OK) |"); - if(state->color_code_ok) fprintf(stderr, "(CRC OK ) |"); //add line break - else fprintf(stderr, "(CRC ERR) |"); //add line break + if(state->color_code_ok) + { + fprintf(stderr, "| (CRC OK ) |"); //add line break + state->dmr_color_code = state->color_code; //set here when voice? otherwise is set off of idle. + } + else + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "| (CRC ERR) |"); //add line break + fprintf (stderr, "%s", KNRM); + } //fprintf(stderr, " VOICE e: \n"); - fprintf(stderr, " VOICE "); + fprintf(stderr, " VOICE "); } /* Perform the SYNC DMR data embedded decoding */ @@ -642,9 +687,10 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) /* Print DMR frame (if needed) */ //DMRVoiceFrameProcess(opts, state); //HERE HERE, was enabled, disabled so I could build - + //JUMP: if(opts->errorbars == 1) { fprintf(stderr, "\n"); } + } /* End processDMRvoice() */ diff --git a/src/dpmr_voice.c b/src/dpmr_voice.c index 406e05d..7a04856 100644 --- a/src/dpmr_voice.c +++ b/src/dpmr_voice.c @@ -163,10 +163,10 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state) { dibit = getDibit (opts, state); - if (opts->inverted_dpmr == 1) - { - dibit = (dibit ^ 2); - } + if (opts->inverted_dpmr == 1) + { + dibit = (dibit ^ 2); + } ambe_fr[j + 4][*w][*x] = (1 & (dibit >> 1)); // bit 1 ambe_fr[j + 4][*y][*z] = (1 & dibit); // bit 0 @@ -467,13 +467,17 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state) //fprintf(stderr, "| TG=%s", CalledID); if(state->dPMRVoiceFS2Frame.CalledIDOk) { + fprintf (stderr, "%s", KGRN); fprintf(stderr, "\n| TG=%s", CalledID); + fprintf (stderr, "%s", KNRM); //strcpy (state->dpmr_target_id, CalledID); //HERE HERE state->dpmr_target_id = CalledID; //fprintf(stderr, " (CRC OK) "); if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1)) { + fprintf (stderr, "%s", KGRN); fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]); + fprintf (stderr, "%s", KNRM); state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0]; } @@ -488,15 +492,19 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state) //fprintf(stderr, "| Src=%s", CallingID); if(state->dPMRVoiceFS2Frame.CallingIDOk) { + fprintf (stderr, "%s", KGRN); fprintf(stderr, "| Src=%s", CallingID); + fprintf (stderr, "%s", KNRM); //strcpy (state->dpmr_caller_id, CallingID); state->dpmr_caller_id = CallingID; - fprintf(stderr, " (CRC OK) \n"); + //fprintf(stderr, " (CRC OK) \n"); } else { + fprintf (stderr, "%s", KRED); fprintf(stderr, " (CRC ERR) \n"); + fprintf (stderr, "%s", KNRM); } #endif /* (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2) */ @@ -583,7 +591,7 @@ void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferO LFSRValue >>= 1; } - /* There are 72 bit to encrypt for voice and 288 bit for data */ + /* There are 72 bit to descramble for voice and 288 bit for data */ for(i = 0; i < NbOfBitToScramble; i++) { BufferOut[i] = (BufferIn[i] ^ S[0]) & 0x01; @@ -613,8 +621,8 @@ void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferO } /* End ScrambleDPmrBit() */ -/* Scrambler used for dPMR encryption / decryption, - * see ETSI TS 102 658 chapter 7.3 for the +/* Scrambler used for dPMR scrambling / descrambling, + * see ETSI TS 102 658 chapter 7.4 for the * polynomial description. * It is a X^9 + X^5 + 1 polynomial. */ void DeInterleave6x12DPmrBit(uint8_t * BufferIn, uint8_t * BufferOut) diff --git a/src/dsd_audio.c b/src/dsd_audio.c index b70e310..a5e277d 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -21,8 +21,6 @@ pa_sample_spec ss; pa_sample_spec tt; pa_sample_spec zz; pa_sample_spec cc; -//pa_channel_map channel_map; - void openPulseOutput(dsd_opts * opts) { @@ -34,68 +32,39 @@ void openPulseOutput(dsd_opts * opts) tt.format = PA_SAMPLE_S16NE; tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle - //fprintf (stderr,"digi rate out = %d\n", opts->pulse_digi_rate_out); - //pa_channel_map_init_stereo(&channel_map); - //ss + if (opts->monitor_input_audio == 1) - //if (opts->frame_dmr == 1 && opts->audio_in_type != 3) { - opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio", &ss, NULL, NULL, NULL); - //opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO Right", &ss, NULL, NULL, NULL); + opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); } //tt pa_channel_map* left = 0; //NULL and 0 are same in this context pa_channel_map* right = 0; //NULL and 0 are same in this context - //pa_channel_map* right; - //pa_channel_map_init(right); - opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, NULL, NULL); - //opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out LEFT", &tt, left, NULL, NULL); - //opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out RIGHT", &tt, right, NULL, NULL); + + if (opts->dmr_stereo == 0) + { + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, NULL, NULL); + + } + if (opts->dmr_stereo == 1) + { + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO LEFT", &tt, left, NULL, NULL); + opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO RIGHT", &tt, right, NULL, NULL); + } + } void openPulseInput(dsd_opts * opts) { - zz.format = PA_SAMPLE_S16NE; - zz.channels = opts->pulse_raw_in_channels; - zz.rate = opts->pulse_raw_rate_in; //48000 - cc.format = PA_SAMPLE_S16NE; cc.channels = opts->pulse_digi_in_channels; cc.rate = opts->pulse_digi_rate_in; //48000 - //zz - if (opts->monitor_input_audio == 1) - { - //opts->pulse_raw_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, "Raw Audio In", &zz, NULL, NULL, NULL); - } - //cc opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, opts->output_name, &cc, NULL, NULL, NULL); } -//playRawAudio may be obsoleted now that I can run these correctly right inside of dsd_symbol -void playRawAudio(dsd_opts * opts, dsd_state * state) -{ - short obuf, outl, i, sample2, something; - something = state->samplesPerSymbol / 1; //1 for buffer steal loops, 5 for rtl loop - //something = 1; - if (opts->audio_in_type == 0 && opts->audio_out_type == 0){ //hack, but might as well for this particular type since its nearly perfect - for (i=0; i < something; i++){ - //read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); - //pa_simple_read(opts->pulse_raw_dev_in, &state->pulse_raw_out_buffer, 2, NULL ); - //obuf = state->pulse_raw_out_buffer / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping - //obuf = state->input_sample_buffer; - //obuf = state->pulse_raw_out_buffer; - //write (opts->audio_out_fd, (void*)&obuf, 2); - //pa_simple_write(opts->pulse_raw_dev_out, (void*)&obuf, 2, NULL); - //pa_simple_write(opts->pulse_digi_dev_out, (void*)&obuf, 2, NULL); - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); - } - } -} //end playRawAudio - void processAudio (dsd_opts * opts, dsd_state * state) @@ -109,7 +78,6 @@ processAudio (dsd_opts * opts, dsd_state * state) // detect max level max = 0; state->audio_out_temp_buf_p = state->audio_out_temp_buf; - //state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; for (n = 0; n < 160; n++) { aout_abs = fabsf (*state->audio_out_temp_buf_p); @@ -118,24 +86,18 @@ processAudio (dsd_opts * opts, dsd_state * state) max = aout_abs; } state->audio_out_temp_buf_p++; - //state->audio_out_temp_buf_pR++; } *state->aout_max_buf_p = max; - //*state->aout_max_buf_pR = max; + state->aout_max_buf_p++; - //state->aout_max_buf_pR++; + state->aout_max_buf_idx++; - //state->aout_max_buf_idxR++; + if (state->aout_max_buf_idx > 24) { state->aout_max_buf_idx = 0; state->aout_max_buf_p = state->aout_max_buf; } - //if (state->aout_max_buf_idxR > 24) - // { - // state->aout_max_buf_idxR = 0; - // state->aout_max_buf_pR = state->aout_max_bufR; - // } // lookup max history for (i = 0; i < 25; i++) @@ -194,7 +156,9 @@ processAudio (dsd_opts * opts, dsd_state * state) // copy audio data to output buffer and upsample if necessary state->audio_out_temp_buf_p = state->audio_out_temp_buf; - if (opts->split == 0) + //we only want to upsample when using sample rates greater than 8k for output, + //hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur. + if (opts->pulse_digi_rate_out > 8000) { for (n = 0; n < 160; n++) { @@ -241,6 +205,147 @@ processAudio (dsd_opts * opts, dsd_state * state) state->audio_out_idx2++; } } + +} + +void +processAudioR (dsd_opts * opts, dsd_state * state) +{ + + int i, n; + float aout_abs, max, gainfactor, gaindelta, maxbuf; + if (opts->audio_gainR == (float) 0) + { + // detect max level + max = 0; + state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; + for (n = 0; n < 160; n++) + { + aout_abs = fabsf (*state->audio_out_temp_buf_pR); + if (aout_abs > max) + { + max = aout_abs; + } + state->audio_out_temp_buf_pR++; + } + *state->aout_max_buf_pR = max; + + state->aout_max_buf_pR++; + + state->aout_max_buf_idxR++; + + if (state->aout_max_buf_idxR > 24) + { + state->aout_max_buf_idxR = 0; + state->aout_max_buf_pR = state->aout_max_bufR; + } + + // lookup max history + for (i = 0; i < 25; i++) + { + maxbuf = state->aout_max_bufR[i]; + if (maxbuf > max) + { + max = maxbuf; + } + } + + // determine optimal gain level + if (max > (float) 0) + { + gainfactor = ((float) 30000 / max); + } + else + { + gainfactor = (float) 50; + } + if (gainfactor < state->aout_gainR) + { + state->aout_gainR = gainfactor; + gaindelta = (float) 0; + } + else + { + if (gainfactor > (float) 50) + { + gainfactor = (float) 50; + } + gaindelta = gainfactor - state->aout_gainR; + if (gaindelta > ((float) 0.05 * state->aout_gainR)) + { + gaindelta = ((float) 0.05 * state->aout_gainR); + } + } + gaindelta /= (float) 160; + } + else + { + gaindelta = (float) 0; + } + + if(opts->audio_gainR >= 0) + { + // adjust output gain + state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; + for (n = 0; n < 160; n++) + { + *state->audio_out_temp_buf_pR = (state->aout_gainR + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_pR); + state->audio_out_temp_buf_pR++; + } + state->aout_gainR += ((float) 160 * gaindelta); + } + + // copy audio data to output buffer and upsample if necessary + state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; + //we only want to upsample when using sample rates greater than 8k for output, + //hard set to 8k for RTL mono and MBE playback, otherwise crackling may occur. + if (opts->pulse_digi_rate_out > 8000) + { + for (n = 0; n < 160; n++) + { + upsample (state, *state->audio_out_temp_buf_pR); + state->audio_out_temp_buf_pR++; + state->audio_out_float_buf_pR += 6; + state->audio_out_idxR += 6; + state->audio_out_idx2R += 6; + } + state->audio_out_float_buf_pR -= (960 + opts->playoffsetR); + // copy to output (short) buffer + for (n = 0; n < 960; n++) + { + if (*state->audio_out_float_buf_pR > 32767.0F) + { + *state->audio_out_float_buf_pR = 32767.0F; + } + else if (*state->audio_out_float_buf_pR < -32768.0F) + { + *state->audio_out_float_buf_pR = -32768.0F; + } + *state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR; + state->audio_out_buf_pR++; + state->audio_out_float_buf_pR++; + } + state->audio_out_float_buf_pR += opts->playoffsetR; + } + else + { + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_pR > 32767.0F) + { + *state->audio_out_temp_buf_pR = 32767.0F; + } + else if (*state->audio_out_temp_buf_pR < -32768.0F) + { + *state->audio_out_temp_buf_pR = -32768.0F; + } + *state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR; + state->audio_out_buf_pR++; + state->audio_out_temp_buf_pR++; + state->audio_out_idxR++; + state->audio_out_idx2R++; + } + } } void @@ -250,10 +355,6 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) short aout_buf[160]; short *aout_buf_p; -// for(n=0; n<160; n++) -// fprintf (stderr,"%d ", ((short*)(state->audio_out_temp_buf))[n]); -// fprintf (stderr,"\n"); - aout_buf_p = aout_buf; state->audio_out_temp_buf_p = state->audio_out_temp_buf; @@ -274,34 +375,6 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) sf_write_short(opts->wav_out_f, aout_buf, 160); - /* - - int n; - short aout_buf[160]; - short *aout_buf_p; - ssize_t result; - - aout_buf_p = aout_buf; - state->audio_out_temp_buf_p = state->audio_out_temp_buf; - for (n = 0; n < 160; n++) - { - if (*state->audio_out_temp_buf_p > (float) 32760) - { - *state->audio_out_temp_buf_p = (float) 32760; - } - else if (*state->audio_out_temp_buf_p < (float) -32760) - { - *state->audio_out_temp_buf_p = (float) -32760; - } - *aout_buf_p = (short) *state->audio_out_temp_buf_p; - aout_buf_p++; - state->audio_out_temp_buf_p++; - } - - result = write (opts->wav_out_fd, aout_buf, 320); - fflush (opts->wav_out_f); - state->wav_out_bytes += 320; - */ } void @@ -310,183 +383,90 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) ssize_t result; if (state->audio_out_idx > opts->delay) - { - // output synthesized speech to sound card + { + // output synthesized speech to sound card if(opts->audio_out_type == 2) { -#ifdef USE_PORTAUDIO - PaError err = paNoError; - do - { - long available = Pa_GetStreamWriteAvailable( opts->audio_out_pa_stream ); - if(available < 0) - err = available; - //fprintf (stderr,"Frames available: %d\n", available); - if( err != paNoError ) - break; - if(available > SAMPLE_RATE_OUT * PA_LATENCY_OUT) - { - //It looks like this might not be needed for very small latencies. However, it's definitely needed for a bit larger ones. - //When PA_LATENCY_OUT == 0.500 I get output buffer underruns if I don't use this. With PA_LATENCY_OUT <= 0.100 I don't see those happen. - //But with PA_LATENCY_OUT < 0.100 I run the risk of choppy audio and stream errors. - fprintf (stderr,"\nSyncing voice output stream\n"); - err = Pa_StopStream( opts->audio_out_pa_stream ); - if( err != paNoError ) - break; - } - - err = Pa_IsStreamActive( opts->audio_out_pa_stream ); - if(err == 0) - { - fprintf (stderr,"Start voice output stream\n"); - err = Pa_StartStream( opts->audio_out_pa_stream ); - } - else if(err == 1) - { - err = paNoError; - } - if( err != paNoError ) - break; - - err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx ); - if( err != paNoError ) - break; - } while(0); - - if( err != paNoError ) - { - fprintf (stderr, "An error occured while using the portaudio output stream\n" ); - fprintf (stderr, "Error number: %d\n", err ); - fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } - -#endif + //go F yourself PA } else - if (opts->monitor_input_audio == 1){ - //pa_simple_flush(opts->pulse_raw_dev_in, NULL); - //pa_simple_flush(opts->pulse_raw_dev_out, NULL); - //state->pulse_raw_out_buffer = 0; - //pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL); + { + //Test just sending it straight on since I think I've figured out the STDIN and RTL for Stereo + pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. + state->audio_out_idx = 0; + } - } - - //two slot audio testing, still need to seperate channels first internally, but this will play them out of different streams - /* - if(state->currentslot == 0 && opts->audio_in_type != 3) + //most likely don't need this seperation anymore with L and R, just push it out without any condional checks + /* + if(state->currentslot == 0 && opts->audio_in_type != 3 && opts->dmr_stereo == 1) { pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. - } - if(state->currentslot == 1 && opts->audio_in_type != 3) - { - pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. - //pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works. + state->audio_out_idx = 0; } - if (opts->audio_in_type == 3) + //if input type is rtl dongle or no dmr stereo...do I need it this way still? + if (opts->audio_in_type == 3 || opts->dmr_stereo == 0) { pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. + state->audio_out_idx = 0; } */ - pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. - state->audio_out_idx = 0; + } if (state->audio_out_idx2 >= 800000) - { - state->audio_out_float_buf_p = state->audio_out_float_buf + 100; - state->audio_out_buf_p = state->audio_out_buf + 100; - memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); - memset (state->audio_out_buf, 0, 100 * sizeof (short)); - state->audio_out_idx2 = 0; - } + { + state->audio_out_float_buf_p = state->audio_out_float_buf + 100; + state->audio_out_buf_p = state->audio_out_buf + 100; + memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); + memset (state->audio_out_buf, 0, 100 * sizeof (short)); + state->audio_out_idx2 = 0; + } + } -#ifdef USE_PORTAUDIO -int getPADevice(char* dev, int input, PaStream** stream) +void +playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) { - int devnum = atoi(dev + 3); - fprintf (stderr,"Using portaudio device %d.\n", devnum); + ssize_t result; - PaError err; - - int numDevices = Pa_GetDeviceCount(); - if( numDevices < 0 ) + if (state->audio_out_idxR > opts->delay) + { + // output synthesized speech to sound card + if(opts->audio_out_type == 2) + { + //go F yourself PA + } + else { - fprintf (stderr, "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices ); - err = numDevices; - goto error; - } - if( devnum >= numDevices) - { - fprintf (stderr, "ERROR: Requested device %d is larger than number of devices.\n", devnum ); - return(1); + pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works. + state->audio_out_idxR = 0; } + /* + //most likely don't need this seperation anymore with L and R, just push it out without any condional checks + if(opts->dmr_stereo == 1) //state->currentslot == 1 && opts->audio_in_type != 3 && opts->dmr_stereo == 1 + { + pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works. + state->audio_out_idxR = 0; + } + */ - const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( devnum ); + } - /* print device name */ -#ifdef WIN32 - { /* Use wide char on windows, so we can show UTF-8 encoded device names */ - wchar_t wideName[MAX_PATH]; - MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1); - wprintf ( L"Name = %s\n", wideName ); - } -#else - fprintf (stderr, "Name = %s\n", deviceInfo->name ); -#endif - if((input == 1) && (deviceInfo->maxInputChannels == 0)) - { - fprintf (stderr, "ERROR: Requested device %d is not an input device.\n", devnum ); - return(1); - } - if((input == 0) && (deviceInfo->maxOutputChannels == 0)) - { - fprintf (stderr, "ERROR: Requested device %d is not an output device.\n", devnum ); - return(1); - } - - //Create stream parameters - PaStreamParameters parameters; - parameters.device = devnum; - parameters.channelCount = 1; /* mono */ - parameters.sampleFormat = paInt16; //Shorts - parameters.suggestedLatency = (input == 1) ? PA_LATENCY_IN : PA_LATENCY_OUT; - parameters.hostApiSpecificStreamInfo = NULL; - - //Open stream - err = Pa_OpenStream( - stream, - (input == 1) ? ¶meters : NULL, - (input == 0) ? ¶meters : NULL, - (input == 1) ? SAMPLE_RATE_IN : SAMPLE_RATE_OUT, - PA_FRAMES_PER_BUFFER, - paClipOff, - NULL /*callback*/, - NULL ); - if( err != paNoError ) goto error; - - return 0; - -error: - fprintf (stderr, "An error occured while initializing a portaudio stream\n" ); - fprintf (stderr, "Error number: %d\n", err ); - fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return err; + if (state->audio_out_idx2R >= 800000) + { + state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100; + state->audio_out_buf_pR = state->audio_out_bufR + 100; + memset (state->audio_out_float_bufR, 0, 100 * sizeof (float)); + memset (state->audio_out_bufR, 0, 100 * sizeof (short)); + state->audio_out_idx2R = 0; + } } -#endif void openAudioOutDevice (dsd_opts * opts, int speed) { - // get info of device/file - /* - if(strncmp(opts->audio_out_dev, "pulse", 5) == 0) - { - opts->audio_out_type == 0; - } - */ if(strncmp(opts->audio_out_dev, "pa:", 3) == 0) { opts->audio_out_type = 2; @@ -518,70 +498,6 @@ openAudioOutDevice (dsd_opts * opts, int speed) fprintf (stderr,"Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); exit(1); } -/* -#ifdef SOLARIS - sample_info_t aset, aget; - - opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); - if (opts->audio_out_fd == -1) - { - fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev); - //exit (1); - } - - // get current - ioctl (opts->audio_out_fd, AUDIO_GETINFO, &aset); - aset.record.sample_rate = speed; - aset.play.sample_rate = speed; - aset.record.channels = 1; - aset.play.channels = 1; - aset.record.precision = 16; - aset.play.precision = 16; - aset.record.encoding = AUDIO_ENCODING_LINEAR; - aset.play.encoding = AUDIO_ENCODING_LINEAR; - - if (ioctl (opts->audio_out_fd, AUDIO_SETINFO, &aset) == -1) - { - fprintf (stderr,"Error setting sample device parameters\n"); - exit (1); - } -#endif - -#if defined(BSD) && !defined(__APPLE__) - - int fmt; - - opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); - if (opts->audio_out_fd == -1) - { - fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev); - opts->audio_out = 0; - //exit(1); - } - - fmt = 0; - if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0) - { - fprintf (stderr,"ioctl reset error \n"); - } - fmt = speed; - if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) - { - fprintf (stderr,"ioctl speed error \n"); - } - fmt = 0; - if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) - { - fprintf (stderr,"ioctl stereo error \n"); - } - fmt = AFMT_S16_LE; - if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) - { - fprintf (stderr,"ioctl setfmt error \n"); - } - -#endif -*/ } fprintf (stderr,"Audio Out Device: %s\n", opts->audio_out_dev); } @@ -661,90 +577,8 @@ openAudioInDevice (dsd_opts * opts) { // this is a device, use old handling, pulse audio now opts->audio_in_type = 0; -/* -#ifdef SOLARIS - sample_info_t aset, aget; - int rgain; - rgain = 64; - - if (opts->split == 1) - { - opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); - } - else - { - opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); - } - if (opts->audio_in_fd == -1) - { - fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); - //exit(1); - } - - // get current - ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset); - - aset.record.sample_rate = SAMPLE_RATE_IN; - aset.play.sample_rate = SAMPLE_RATE_IN; - aset.record.channels = 1; - aset.play.channels = 1; - aset.record.precision = 16; - aset.play.precision = 16; - aset.record.encoding = AUDIO_ENCODING_LINEAR; - aset.play.encoding = AUDIO_ENCODING_LINEAR; - aset.record.port = AUDIO_LINE_IN; - aset.record.gain = rgain; - - if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1) - { - fprintf (stderr,"Error setting sample device parameters\n"); - exit (1); - } -#endif -*/ -/* -#if defined(BSD) && !defined(__APPLE__) - int fmt; - - if (opts->split == 1) - { - opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); - } - else - { - opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); - } - - if (opts->audio_in_fd == -1) - { - fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); - opts->audio_out = 0; - } - - fmt = 0; - if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0) - { - fprintf (stderr,"ioctl reset error \n"); - } - fmt = SAMPLE_RATE_IN; - if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0) - { - fprintf (stderr,"ioctl speed error \n"); - } - fmt = 0; - if (ioctl (opts->audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0) - { - fprintf (stderr,"ioctl stereo error \n"); - } - fmt = AFMT_S16_LE; - if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) - { - fprintf (stderr,"ioctl setfmt error \n"); - } -#endif -*/ - } + } } if (opts->split == 1) diff --git a/src/dsd_dibit.c b/src/dsd_dibit.c index 76672c3..1ef3820 100644 --- a/src/dsd_dibit.c +++ b/src/dsd_dibit.c @@ -185,9 +185,16 @@ use_symbol (dsd_opts* opts, dsd_state* state, int symbol) } if (state->dibit_buf_p > state->dibit_buf + 900000) - { - state->dibit_buf_p = state->dibit_buf + 200; - } + { + state->dibit_buf_p = state->dibit_buf + 200; + } + + //dmr buffer + if (state->dmr_payload_p > state->dmr_payload_buf + 900000) + { + state->dmr_payload_p = state->dmr_payload_buf + 200; + } + //dmr buffer end } static int @@ -211,6 +218,7 @@ invert_dibit(int dibit) } static 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)) @@ -252,8 +260,10 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) return (0); // +1 } } + 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 == 9) || (state->synctype == 11) || (state->synctype == 13) || + (state->synctype == 17) ) { // 1 -P25p1 @@ -263,7 +273,6 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) // 11 -DMR (inverted signal voice frame) // 13 -DMR (inverted signal data frame) // 17 -NXDN (inverted data frame) - // int valid; int dibit; @@ -361,64 +370,12 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) } state->last_dibit = dibit; - //test loading up a shift register and printing it to stderr - //di-bit shift register for hex values - //check for which dibit is equal to which half-nibble - if (dibit == 0){state->hexbuf = 0x0;} //+1 - if (dibit == 1){state->hexbuf = 0x1;} //+3 - if (dibit == 2){state->hexbuf = 0x2;} //-1 - if (dibit == 3){state->hexbuf = 0x3;} //-3 - state->sr_0 = (state->sr_0 << 2) | (state->sr_1 >> 62); - state->sr_1 = (state->sr_1 << 2) | (state->sr_2 >> 62); - state->sr_2 = (state->sr_2 << 2) | (state->sr_3 >> 62); - state->sr_3 = (state->sr_3 << 2) | (state->sr_4 >> 62); - state->sr_4 = (state->sr_4 << 2) | (state->sr_5 >> 62); - state->sr_5 = (state->sr_5 << 2) | (state->sr_6 >> 62); - state->sr_6 = state->sr_6 << 2; - state->sr_6 |= state->hexbuf; - if (1 == 2) //disable this later on - { - fprintf (stderr, "\nsr_0 = %16llX \n", state->sr_0); - fprintf (stderr, "sr_1 = %16llX \n", state->sr_1); - fprintf (stderr, "sr_2 = %16llX \n", state->sr_2); - fprintf (stderr, "sr_3 = %16llX \n", state->sr_3); - fprintf (stderr, "sr_4 = %16llX \n", state->sr_4); - fprintf (stderr, "sr_5 = %16llX \n", state->sr_5); - fprintf (stderr, "sr_6 = %16llX \n", state->sr_6); - /* - printw ("sr_0 = %16llX \n", sr_0); - printw ("sr_1 = %16llX \n", sr_1); - printw ("sr_2 = %16llX \n", sr_2); - printw ("sr_3 = %16llX \n", sr_3); - printw ("sr_4 = %16llX \n", sr_4); - printw ("sr_5 = %16llX \n", sr_5); - printw ("sr_6 = %16llX \n", sr_6); - */ - } - - if ( state->sr_5 & 0xFFFFF == 0xDDF5D) //disable this later on - { - fprintf (stderr, "\nsr_0 = %16llX \n", state->sr_0); - fprintf (stderr, "sr_1 = %16llX \n", state->sr_1); - fprintf (stderr, "sr_2 = %16llX \n", state->sr_2); - fprintf (stderr, "sr_3 = %16llX \n", state->sr_3); - fprintf (stderr, "sr_4 = %16llX \n", state->sr_4); - fprintf (stderr, "sr_5 = %16llX \n", state->sr_5); - fprintf (stderr, "sr_6 = %16llX \n", state->sr_6); - /* - printw ("sr_0 = %16llX \n", sr_0); - printw ("sr_1 = %16llX \n", sr_1); - printw ("sr_2 = %16llX \n", sr_2); - printw ("sr_3 = %16llX \n", sr_3); - printw ("sr_4 = %16llX \n", sr_4); - printw ("sr_5 = %16llX \n", sr_5); - printw ("sr_6 = %16llX \n", sr_6); - */ - } - - *state->dibit_buf_p = dibit; state->dibit_buf_p++; + //dmr buffer + *state->dmr_payload_p = dibit; + state->dmr_payload_p++; + //dmr buffer end return dibit; } } @@ -447,9 +404,7 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s // state->sbuf[state->sidx] = symbol; - // - //state->pulse_raw_out_buffer = symbol; - // + if (out_analog_signal != NULL) { *out_analog_signal = symbol; diff --git a/src/dsd_file.c b/src/dsd_file.c index 64b96ff..de168b0 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -76,7 +76,6 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d) for (i = 0; i < 7; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more { b = 0; - for (j = 0; j < 8; j++) { b = b << 1; diff --git a/src/dsd_frame.c b/src/dsd_frame.c index ea83287..38dc782 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -35,14 +35,20 @@ printFrameInfo (dsd_opts * opts, dsd_state * state) } if (state->nac != 0) { + fprintf (stderr, "%s", KCYN); fprintf (stderr,"nac: [%4X] ", state->nac); + fprintf (stderr, "%s", KNRM); } if (opts->verbose > 1) { + fprintf (stderr, "%s", KGRN); fprintf (stderr,"src: [%8i] ", state->lastsrc); + fprintf (stderr, "%s", KNRM); } + fprintf (stderr, "%s", KGRN); fprintf (stderr,"tg: [%5i] ", state->lasttg); + fprintf (stderr, "%s", KNRM); } void @@ -168,12 +174,15 @@ processFrame (dsd_opts * opts, dsd_state * state) processDSTAR_HD (opts, state); return; } - - else if ((state->synctype >= 10) && (state->synctype <= 13)) + //Start DMR Types + else if ((state->synctype >= 10) && (state->synctype <= 13) || (state->synctype == 32) || (state->synctype == 33) || (state->synctype == 34) ) //32-34 DMR MS and RC { + //disable so radio id doesn't blink in and out during ncurses and aggressive_framesync state->nac = 0; - state->lastsrc = 0; - state->lasttg = 0; + //state->lastsrc = 0; + //state->lasttg = 0; + //state->lastsrcR = 0; + //state->lasttgR = 0; if (opts->errorbars == 1) { if (opts->verbose > 0) @@ -182,21 +191,63 @@ processFrame (dsd_opts * opts, dsd_state * state) //fprintf (stderr,"inlvl: %2i%% ", level); } } - if ((state->synctype == 11) || (state->synctype == 12)) + if ( (state->synctype == 11) || (state->synctype == 12) || (state->synctype == 32) ) //DMR Voice Modes { - if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) + if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL) && opts->dmr_stereo == 0) { openMbeOutFile (opts, state); } sprintf (state->fsubtype, " VOICE "); - processDMRvoice (opts, state); + if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo + { + processDMRvoice (opts, state); + } + if (opts->dmr_stereo == 0 && state->synctype == 32) + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, "Please use the -T option to handle MS Mode with DMR Stereo TDMA Handling\n"); + fprintf (stderr, "%s", KNRM); + } + if (opts->dmr_stereo == 1) + { + state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames + if (state->synctype > 31 ) + { + dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only) + } + else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap + } } + else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data + { + if (opts->dmr_stereo == 0) + { + closeMbeOutFile (opts, state); + state->err_str[0] = 0; + fprintf (stderr, "%s", KRED); + fprintf (stderr, "Please use the -T option to handle MS Mode with DMR Stereo TDMA Handling\n"); + fprintf (stderr, "%s", KNRM); + } + if (opts->dmr_stereo == 1) + { + dmrMSData (opts, state); + } + } else + { + if (opts->dmr_stereo == 0) { closeMbeOutFile (opts, state); state->err_str[0] = 0; processDMRdata (opts, state); } + //switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata + if (opts->dmr_stereo == 1) + { + state->dmr_stereo = 0; //set the state to zero for handling pure data frames + processDMRdata (opts, state); + } + } return; } else if ((state->synctype >= 2) && (state->synctype <= 5)) @@ -244,7 +295,20 @@ processFrame (dsd_opts * opts, dsd_state * state) processProVoice (opts, state); return; } - //LEH dPMR + //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 "); + processYSF(opts, state); + return; + } + //dPMR else if ((state->synctype == 20) || (state->synctype == 24)) { /* dPMR Frame Sync 1 */ @@ -255,7 +319,6 @@ processFrame (dsd_opts * opts, dsd_state * state) /* dPMR Frame Sync 2 */ fprintf(stderr, "dPMR Frame Sync 2 "); - //state->rf_mod = GFSK_MODE; state->nac = 0; state->lastsrc = 0; state->lasttg = 0; @@ -264,7 +327,6 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->verbose > 0) { level = (int) state->max / 164; - //fprintf(stderr, "inlvl: %2i%% ", level); } } state->nac = 0; @@ -290,7 +352,7 @@ processFrame (dsd_opts * opts, dsd_state * state) fprintf(stderr, "dPMR Frame Sync 4 "); } //dPMR - else + else //P25 { // Read the NAC, 12 bits j = 0; diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 85e1a80..546580b 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -17,9 +17,8 @@ #include "dsd.h" #include -//#include -//borrowed from LEH for 'improved NXDN sync detection' +//borrowed from DSDcc for 'improved NXDN sync detection' int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr) { int Compare = -1; @@ -50,7 +49,6 @@ int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr) return Compare; } /* End strncmperr() */ -//end LEH time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp @@ -140,15 +138,21 @@ getFrameSync (dsd_opts * opts, dsd_state * state) * 26 = -dPMR Frame Sync 3 * 27 = -dPMR Frame Sync 4 * 28 = +NXDN (sync only) - * 29 = -NXDN (sync only + * 29 = -NXDN (sync only) + * 30 = +YSF + * 31 = -YSF + * 32 = DMR MS Voice + * 33 = DMR MS Data + * 34 = DMR RC Data */ int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt; char synctest[25]; - char synctest12[13]; //LEH DPMR + char synctest12[13]; //dPMR char synctest18[19]; char synctest32[33]; + char synctest20[21]; //YSF char modulation[8]; char *synctest_p; char synctest_buf[10240]; @@ -169,6 +173,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) synctest12[12] = 0; synctest18[18] = 0; synctest32[32] = 0; + synctest20[20] = 0; synctest_pos = 0; synctest_p = synctest_buf + 10; sync = 0; @@ -246,9 +251,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } if (state->dibit_buf_p > state->dibit_buf + 900000) - { - state->dibit_buf_p = state->dibit_buf + 200; - } + { + state->dibit_buf_p = state->dibit_buf + 200; + } //determine dibit state if (symbol > 0) @@ -264,6 +269,49 @@ getFrameSync (dsd_opts * opts, dsd_state * state) dibit = 51; // '3' } + //digitize test for storing dibits in buffer correctly for dmr recovery + + if (state->dmr_payload_p > state->dmr_payload_buf + 900000) + { + state->dmr_payload_p = state->dmr_payload_buf + 200; + } + + int valid; + //running estimate_symbol causes an issue with P25 syncing properly + if (opts->frame_p25p1 != 1) + { + valid = estimate_symbol(state->rf_mod, &(state->p25_heuristics), state->last_dibit, symbol, &dibit); + } + + if (opts->frame_dmr == 1 && valid == 0) //opts->dmr_stereo + { + if (symbol > state->center) + { + if (symbol > state->umid) + { + *state->dmr_payload_p = 1; // +3 + } + else + { + *state->dmr_payload_p = 0; // +1 + } + } + else + { + if (symbol < state->lmid) + { + *state->dmr_payload_p = 3; // -3 + } + else + { + *state->dmr_payload_p = 2; // -1 + } + } + state->dmr_payload_p++; + + } + // end digitize and dmr buffer testing + *synctest_p = dibit; if (t >= 18) { @@ -502,7 +550,53 @@ 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 + { + if (0 == 0) //opts->inverted_ysf == 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); + } + } + } + if(opts->frame_ysf == 1) //(opts->frame_ysf == 1 + { + if (0 == 0) //opts->inverted_ysf == 1 + { + 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); + } + } + } + //end YSF sync //dPMR sync strncpy(synctest, (synctest_p - 23), 24); strncpy(synctest12, (synctest_p - 11), 12); @@ -512,7 +606,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { if(strcmp(synctest, DPMR_FRAME_SYNC_1) == 0) { - fprintf (stderr, "+dPMR FS1\n"); + //fprintf (stderr, "+dPMR FS1\n"); } if(strcmp(synctest12, DPMR_FRAME_SYNC_2) == 0) { @@ -528,22 +622,26 @@ 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) { - fprintf (stderr, "+dPMR FS3 \n"); + //fprintf (stderr, "+dPMR FS3 \n"); } if(strcmp(synctest, DPMR_FRAME_SYNC_4) == 0) { - fprintf (stderr, "+dPMR FS4 \n"); + //fprintf (stderr, "+dPMR FS4 \n"); } } if (opts->inverted_dpmr == 1) { if(strcmp(synctest, INV_DPMR_FRAME_SYNC_1) == 0) { - fprintf (stderr, "-dPMR FS1 \n"); + //fprintf (stderr, "-dPMR FS1 \n"); } if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_2) == 0) { @@ -560,15 +658,19 @@ 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) { - fprintf (stderr, "-dPMR FS3 \n"); + //fprintf (stderr, "-dPMR FS3 \n"); } if(strcmp(synctest, INV_DPMR_FRAME_SYNC_4) == 0) { - fprintf (stderr, "-dPMR FS4 \n"); + //fprintf (stderr, "-dPMR FS4 \n"); } } } @@ -576,7 +678,97 @@ getFrameSync (dsd_opts * opts, dsd_state * state) //New DMR Sync if (opts->frame_dmr == 1) { - if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0)) + + if(strcmp (synctest, DMR_MS_DATA_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + //state->directmode = 0; + //fprintf (stderr, "DMR MS Data"); + if (0 == 0) //opts->inverted_dmr + { + // data frame + sprintf(state->ftype, "DMR MS"); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "+DMR MS Data", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 33) //33 + { + //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 + } + } + //not sure if this should be here, RC data should only be present in vc6? + if(strcmp (synctest, DMR_RC_DATA_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + //state->directmode = 0; + //fprintf (stderr, "DMR RC DATA\n"); + state->dmr_ms_rc == 1; //set flag for RC data, then process accordingly and reset back to 0 afterwards + if (0 == 0) //opts->inverted_dmr + { + // voice frame + sprintf(state->ftype, "DMR RC"); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "+DMR RC Data", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 34) + { + //state->firstframe = 1; + } + state->lastsynctype = 34; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (34); + } + } + + if(strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + //state->directmode = 0; + //fprintf (stderr, "DMR MS VOICE\n"); + if (0 == 0) //opts->inverted_dmr + { + // voice frame + sprintf(state->ftype, "DMR MS"); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "+DMR MS Voice", synctest_pos + 1, modulation); + } + if (state->lastsynctype != 32) + { + //state->firstframe = 1; + } + state->lastsynctype = 32; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (32); + } + } + + //if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0)) + if (strcmp (synctest, DMR_BS_DATA_SYNC) == 0) { state->carrier = 1; state->offset = synctest_pos; @@ -594,7 +786,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 10; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (10); @@ -614,7 +805,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 11; if ( opts->monitor_input_audio == 1) { - pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (11); } @@ -638,7 +829,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 10; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (10); @@ -658,7 +848,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 11; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (11); @@ -683,7 +872,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 10; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (10); @@ -692,7 +880,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // inverted voice frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } @@ -703,13 +891,13 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 11; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (11); } } /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) */ - if((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0)) + //if((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0)) + if(strcmp (synctest, DMR_BS_VOICE_SYNC) == 0) { state->carrier = 1; state->offset = synctest_pos; @@ -720,7 +908,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // voice frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); } @@ -729,20 +917,24 @@ 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); + } return (12); } + else { // inverted data frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } state->lastsynctype = 13; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (13); @@ -756,7 +948,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->min = ((state->min) + lmin) / 2; state->currentslot = 0; state->directmode = 1; //Direct mode - if (opts->inverted_dmr == 0) + if (opts->inverted_dmr == 0 && opts->dmr_stereo == 0) { // voice frame sprintf(state->ftype, "DMR "); @@ -771,7 +963,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 12; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (12); @@ -780,7 +971,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // inverted data frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } @@ -800,7 +991,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // voice frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation); } @@ -811,7 +1002,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 12; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (12); @@ -820,14 +1010,14 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { // inverted data frame sprintf(state->ftype, "DMR "); - if (opts->errorbars == 1) + if (opts->errorbars == 1 && opts->dmr_stereo == 0) { printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation); } state->lastsynctype = 13; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (13); @@ -835,7 +1025,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } //End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0) } //End if (opts->frame_dmr == 1) - //end LEH DMR Sync + //end DMR Sync if (opts->frame_provoice == 1) { strncpy (synctest32, (synctest_p - 31), 32); @@ -855,7 +1045,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 14; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (14); @@ -875,7 +1065,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 15; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (15); @@ -885,8 +1075,6 @@ getFrameSync (dsd_opts * opts, dsd_state * state) if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1)) { strncpy (synctest18, (synctest_p - 17), 18); - //if ((strcmp (synctest18, NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_VOICE_SYNC) == 0)) //or is this the double up test? - //borrowing from LEH here WOW! This works so much better, its not even a joke if ((strncmperr (synctest18, NXDN_BS_VOICE_SYNC, 18, 1) == 0) || (strncmperr (synctest18, NXDN_MS_VOICE_SYNC, 18, 1) == 0)) { now = time(NULL); @@ -903,7 +1091,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf (state->ftype, "NXDN48 "); //get rid of spaces if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } if (opts->errorbars == 1) @@ -917,7 +1105,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf (state->ftype, "NXDN96"); if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } if (opts->errorbars == 1) @@ -967,7 +1155,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 9; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (9); @@ -1009,7 +1197,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 16; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (16); @@ -1052,7 +1240,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 17; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (17); @@ -1082,7 +1270,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 6; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (6); @@ -1102,7 +1290,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 7; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (7); @@ -1122,7 +1310,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 18; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (18); @@ -1142,7 +1330,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) state->lastsynctype = 19; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); + pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (19); @@ -1212,7 +1400,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state) return (4); } - else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) || (strcmp (synctest, DMR_MS_VOICE_SYNC) != 0))) + + //dmr desync handling, causes issues with TDMA stereo (MS especially), consider removing + //may have been because we had BS Voice twice on here, seems okay, continue testing + /* + else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) )) { state->carrier = 1; state->offset = synctest_pos; @@ -1221,17 +1413,18 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf (state->ftype, "(DMR) "); if (opts->errorbars == 1) { - printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation); + //printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation); } state->lastsynctype = -1; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } return (11); } - else if ((state->lastsynctype == 12) && ((strcmp (synctest, DMR_BS_DATA_SYNC) != 0) || (strcmp (synctest, DMR_MS_DATA_SYNC) != 0))) + */ + + else if ( (state->lastsynctype == 32) && (strcmp (synctest, DMR_MS_VOICE_SYNC) != 0) ) { state->carrier = 1; state->offset = synctest_pos; @@ -1240,18 +1433,76 @@ getFrameSync (dsd_opts * opts, dsd_state * state) sprintf (state->ftype, "(DMR) "); if (opts->errorbars == 1) { - printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation); + //printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation); } state->lastsynctype = -1; if ( opts->monitor_input_audio == 1) { - //pa_simple_drain(opts->pulse_raw_dev_out, NULL); pa_simple_flush(opts->pulse_raw_dev_out, NULL); } - return (12); + return (32); //32 } - } - } + + else if ( (state->lastsynctype == 33) && (strcmp (synctest, DMR_MS_DATA_SYNC) != 0) ) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(DMR) "); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (33); //33 + } + else if ( (state->lastsynctype == 34) && (strcmp (synctest, DMR_RC_DATA_SYNC) != 0) ) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(DMR) "); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (34); //34 + } + + else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) )) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + sprintf (state->ftype, "(DMR) "); + if (opts->errorbars == 1) + { + //printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation); + } + state->lastsynctype = -1; + if ( opts->monitor_input_audio == 1) + { + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + } + return (11); //11 + } + + //DMR desync + + } //if t == 24 + } // t >= 18 if (exitflag == 1) { @@ -1294,12 +1545,9 @@ getFrameSync (dsd_opts * opts, dsd_state * state) return (-1); } } - if ( opts->monitor_input_audio == 1 && (time(NULL) - now) > 1 ) //okay, still something going on, latency issues - //if ( opts->monitor_input_audio == 1) - { - //playRawAudio(opts, state); //this is on line 21 in dsd_audio.c - } + } return (-1); } +//1111 diff --git a/src/dsd_main.c b/src/dsd_main.c index 9fa5f92..e183c86 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -26,17 +26,6 @@ #include "provoice_const.h" #include "git_ver.h" -//pretty pretty colors - -#define KNRM "\x1B[0m" -#define KRED "\x1B[31m" -#define KGRN "\x1B[32m" -#define KYEL "\x1B[33m" -#define KBLU "\x1B[34m" -#define KMAG "\x1B[35m" -#define KCYN "\x1B[36m" -#define KWHT "\x1B[37m" - int pretty_colors() { fprintf (stderr,"%sred\n", KRED); @@ -84,6 +73,10 @@ noCarrier (dsd_opts * opts, dsd_state * state) { state->dibit_buf_p = state->dibit_buf + 200; memset (state->dibit_buf, 0, sizeof (int) * 200); + //dmr buffer + state->dmr_payload_p = state->dibit_buf + 200; + memset (state->dmr_payload_buf, 0, sizeof (int) * 200); + //dmr buffer end if (opts->mbe_out_f != NULL) { closeMbeOutFile (opts, state); @@ -93,15 +86,18 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->carrier = 0; state->max = 15000; state->min = -15000; - state->center = 0; + state->center = 0; //quick disable for dmr testing with buffer state->err_str[0] = 0; state->err_strR[0] = 0; sprintf (state->fsubtype, " "); sprintf (state->ftype, " "); state->errs = 0; state->errs2 = 0; + //should I disable this or not? state->lasttg = 0; state->lastsrc = 0; + state->lasttgR = 0; + state->lastsrcR = 0; state->lastp25type = 0; state->repeat = 0; state->nac = 0; @@ -110,15 +106,26 @@ noCarrier (dsd_opts * opts, dsd_state * state) sprintf (state->slot1light, " slot1 "); state->firstframe = 0; if (opts->audio_gain == (float) 0) - { - state->aout_gain = 25; - } + { + state->aout_gain = 25; + } + + if (opts->audio_gainR == (float) 0) + { + state->aout_gainR = 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; + + memset (state->aout_max_bufR, 0, sizeof (float) * 200); + state->aout_max_buf_pR = state->aout_max_bufR; + state->aout_max_buf_idxR = 0; + sprintf (state->algid, "________"); sprintf (state->keyid, "________________"); mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + mbe_initMbeParms (state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2); } void @@ -151,11 +158,13 @@ initOpts (dsd_opts * opts) #endif opts->split = 0; opts->playoffset = 0; + opts->playoffsetR = 0; opts->mbe_out_dir[0] = 0; opts->mbe_out_file[0] = 0; opts->mbe_out_path[0] = 0; opts->mbe_out_f = NULL; opts->audio_gain = 0; + opts->audio_gainR = 0; opts->audio_out = 1; opts->wav_out_file[0] = 0; opts->wav_out_f = NULL; @@ -163,7 +172,7 @@ initOpts (dsd_opts * opts) opts->serial_baud = 115200; sprintf (opts->serial_dev, "/dev/ttyUSB0"); opts->resume = 0; - opts->frame_dstar = 1; + opts->frame_dstar = 1; opts->frame_x2tdma = 1; opts->frame_p25p1 = 1; opts->frame_nxdn48 = 0; @@ -200,13 +209,16 @@ initOpts (dsd_opts * opts) opts->pulse_digi_in_channels = 1; //2 opts->pulse_digi_out_channels = 1; //2 - sprintf (opts->output_name, "Default Channel"); + sprintf (opts->output_name, "Auto Detect"); opts->pulse_flush = 1; //set 0 to flush, 1 for flushed opts->use_ncurses_terminal = 0; opts->payload = 0; opts->EncryptionMode = MODE_UNENCRYPTED; opts->inverted_dpmr = 0; + opts->dmr_stereo = 0; + opts->aggressive_framesync = 1; //more aggressive to combat wonk wonk voice decoding + //opts->audio_in_type = 0; } void @@ -218,13 +230,18 @@ initState (dsd_state * state) state->dibit_buf = malloc (sizeof (int) * 1000000); state->dibit_buf_p = state->dibit_buf + 200; memset (state->dibit_buf, 0, sizeof (int) * 200); + //dmr buffer -- double check this set up + state->dmr_payload_buf = malloc (sizeof (int) * 1000000); + state->dmr_payload_p = state->dmr_payload_buf + 200; + memset (state->dmr_payload_buf, 0, sizeof (int) * 200); + //dmr buffer end state->repeat = 0; state->audio_out_buf = malloc (sizeof (short) * 1000000); state->audio_out_bufR = malloc (sizeof (short) * 1000000); memset (state->audio_out_buf, 0, 100 * sizeof (short)); memset (state->audio_out_bufR, 0, 100 * sizeof (short)); state->audio_out_buf_p = state->audio_out_buf + 100; - state->audio_out_buf_pR = state->audio_out_buf + 100; + state->audio_out_buf_pR = state->audio_out_bufR + 100; state->audio_out_float_buf = malloc (sizeof (float) * 1000000); state->audio_out_float_bufR = malloc (sizeof (float) * 1000000); memset (state->audio_out_float_buf, 0, 100 * sizeof (float)); @@ -296,6 +313,11 @@ initState (dsd_state * state) memset (state->aout_max_buf, 0, sizeof (float) * 200); state->aout_max_buf_p = state->aout_max_buf; state->aout_max_buf_idx = 0; + + memset (state->aout_max_bufR, 0, sizeof (float) * 200); + state->aout_max_buf_pR = state->aout_max_bufR; + state->aout_max_buf_idxR = 0; + state->samplesPerSymbol = 10; state->symbolCenter = 4; sprintf (state->algid, "________"); @@ -304,10 +326,17 @@ initState (dsd_state * state) state->cur_mp = malloc (sizeof (mbe_parms)); state->prev_mp = malloc (sizeof (mbe_parms)); state->prev_mp_enhanced = malloc (sizeof (mbe_parms)); + + state->cur_mp2 = malloc (sizeof (mbe_parms)); + state->prev_mp2 = malloc (sizeof (mbe_parms)); + state->prev_mp_enhanced2 = malloc (sizeof (mbe_parms)); + mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced); + mbe_initMbeParms (state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2); state->p25kid = 0; state->debug_audio_errors = 0; + state->debug_audio_errorsR = 0; state->debug_header_errors = 0; state->debug_header_critical_errors = 0; @@ -322,24 +351,51 @@ initState (dsd_state * state) state->dpmr_caller_id = 0; state->dpmr_target_id = 0; - state->payload_mi = 0; + state->payload_mi = 0; + state->payload_miR = 0; state->payload_mfid = 0; + state->payload_mfidR = 0; state->payload_algid = 0; + state->payload_algidR = 0; state->payload_keyid = 0; + state->payload_keyidR = 0; sprintf (state->dmr_branding, " "); - sprintf (state->dmr_callsign[0], ""); - sprintf (state->dmr_callsign[1], ""); - sprintf (state->dmr_callsign[2], ""); - sprintf (state->dmr_callsign[3], ""); - sprintf (state->dmr_lrrp[0], ""); - sprintf (state->dmr_lrrp[1], ""); - sprintf (state->dmr_lrrp[2], ""); - sprintf (state->dmr_lrrp[3], ""); - sprintf (state->dmr_lrrp[4], ""); - sprintf (state->dmr_lrrp[5], ""); + sprintf (state->dmr_callsign[0][0], ""); + sprintf (state->dmr_callsign[0][1], ""); + sprintf (state->dmr_callsign[0][2], ""); + sprintf (state->dmr_callsign[0][3], ""); + sprintf (state->dmr_callsign[0][4], ""); + sprintf (state->dmr_callsign[0][5], ""); + sprintf (state->dmr_callsign[1][0], ""); + sprintf (state->dmr_callsign[1][1], ""); + sprintf (state->dmr_callsign[1][2], ""); + sprintf (state->dmr_callsign[1][3], ""); + sprintf (state->dmr_callsign[1][4], ""); + sprintf (state->dmr_callsign[1][5], ""); + sprintf (state->dmr_lrrp[0][0], ""); + sprintf (state->dmr_lrrp[0][1], ""); + sprintf (state->dmr_lrrp[0][2], ""); + sprintf (state->dmr_lrrp[0][3], ""); + sprintf (state->dmr_lrrp[0][4], ""); + sprintf (state->dmr_lrrp[0][5], ""); + sprintf (state->dmr_lrrp[1][0], ""); + sprintf (state->dmr_lrrp[1][1], ""); + sprintf (state->dmr_lrrp[1][2], ""); + sprintf (state->dmr_lrrp[1][3], ""); + sprintf (state->dmr_lrrp[1][4], ""); + sprintf (state->dmr_lrrp[1][5], ""); state->K = 0; + state->dmr_stereo = 0; + state->dmrburstL = 17; //initialize at higher value than possible + state->dmrburstR = 17; //17 in char array is set for ERR + state->dmr_so = 0; + state->dmr_soR = 0; + state->dmr_fid = 0; + state->dmr_fidR = 0; + + memset(state->dstarradioheader, 0, 41); #ifdef TRACE_DSD state->debug_sample_index = 0; @@ -380,7 +436,7 @@ usage () fprintf (stderr," -g Audio output gain (default = 0 = auto, disable = -1)\n"); fprintf (stderr," -w Output synthesized speech to a .wav file\n"); //fprintf (stderr," -a Display port audio devices\n"); - //fprintf (stderr," -W Monitor Source Audio When No Sync Detected (WIP!)\n"); + fprintf (stderr," -W Monitor Source Audio When No Sync Detected (WIP!)\n"); fprintf (stderr,"\n"); fprintf (stderr,"RTL-SDR options:\n"); fprintf (stderr," -c RTL-SDR Frequency\n"); @@ -427,8 +483,14 @@ usage () fprintf (stderr," -M Min/Max buffer size for QPSK decision point tracking\n"); fprintf (stderr," (default=15)\n"); fprintf (stderr," -n Reset P25 Heuristics and initState variables on mixed signal decoding\n"); - fprintf (stderr," Helps when decoding mixed signal types at same time\n"); - fprintf (stderr," (WiP! May Cause Slow Memory Leak - Experimental)\n"); + fprintf (stderr," Helps when decoding mixed signal types (P25P1) at same time\n"); + fprintf (stderr," (WiP! May Cause Slow Memory Leak or System Hang - Experimental)\n"); + fprintf (stderr," -T Enable DMR TDMA Stereo Voice (Two Slot Dual Voices)\n"); + fprintf (stderr," This feature will open two streams for slot 1 voice and slot 2 voice\n"); + fprintf (stderr," May Cause Skipping or sync issues if bad signal/errors\n"); + fprintf (stderr," -F Enable DMR TDMA Stereo Passive Frame Sync\n"); + fprintf (stderr," This feature will attempt to resync less often due to excessive voice errors\n"); + fprintf (stderr," Use if skipping occurs, but may cause wonky audio due to loss of good sync\n"); fprintf (stderr," -Z Log MBE Payload to console\n"); fprintf (stderr,"\n"); fprintf (stderr,"Report bugs to: https://github.com/lwvmobile/dsd-fme/issues \n"); @@ -438,15 +500,23 @@ usage () void liveScanner (dsd_opts * opts, dsd_state * state) { -//need to use this area to configure audio rates for different sources if not pulse -if (opts->audio_in_type == 1) //if stdin, switch to 8000 and single channel audio +//still need this section mostly due the the crackling on the rtl dongle when upsampled +//probably need to dig a little deeper, maybe inlvl releated? +if (opts->audio_in_type == 1) { - opts->pulse_digi_rate_out = 8000; //stdin needs 8000 output, could have sworn this was working with 48000 + opts->pulse_digi_rate_out = 48000; //change to 48K/1 for STDIN input opts->pulse_digi_out_channels = 1; + if (opts->dmr_stereo == 1) + { + opts->pulse_digi_rate_out = 24000; //stdin needs 24000 by 2 channel for DMR TDMA Stereo output + opts->pulse_digi_out_channels = 2; + fprintf (stderr, "STDIN Audio Rate Out set to 24000 Khz/2 Channel \n"); + } + else fprintf (stderr, "STDIN Audio Rate Out set to 48000 Khz/1 Channel \n"); opts->pulse_raw_rate_out = 48000; opts->pulse_raw_out_channels = 1; - fprintf (stderr, "STDIN Audio Rate Out set to 8000 Khz/1 Channel \n"); + } #ifdef USE_PORTAUDIO @@ -465,11 +535,20 @@ if (opts->audio_in_type == 1) //if stdin, switch to 8000 and single channel audi #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { - opts->pulse_digi_rate_out = 8000; //if rtl, switch to 8000 and 1 channel + //still need this section mostly due the the crackling on the rtl dongle when upsampled + //probably need to dig a little deeper, maybe inlvl releated? + opts->pulse_digi_rate_out = 8000; //revert to 8K/1 for RTL input, random crackling otherwise opts->pulse_digi_out_channels = 1; + if (opts->dmr_stereo == 1) + { + opts->pulse_digi_rate_out = 24000; //rtl needs 24000 by 2 channel for DMR TDMA Stereo output + opts->pulse_digi_out_channels = 2; //minimal crackling 'may' be observed, not sure, can't test to see on DMR with RTL + fprintf (stderr, "RTL Audio Rate Out set to 24000 Khz/2 Channel \n"); + } + else fprintf (stderr, "RTL Audio Rate Out set to 48000 Khz/1 Channel \n"); opts->pulse_raw_rate_out = 48000; opts->pulse_raw_out_channels = 1; - fprintf (stderr, "RTL Audio Rate Out set to 8000 Khz/1 Channel \n"); + open_rtlsdr_stream(opts); } #endif @@ -669,12 +748,12 @@ main (int argc, char **argv) initOpts (&opts); initState (&state); - InitAllFecFunction(); //HERE + InitAllFecFunction(); exitflag = 0; signal (SIGINT, sigfun); - while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:Y:K:NWrlZ")) != -1) + while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:Y:K:NWrlZTF")) != -1) { opterr = 0; switch (c) @@ -771,8 +850,10 @@ main (int argc, char **argv) case 'W': //monitor_input_audio if no sync opts.monitor_input_audio = 1; + fprintf (stderr, "%s", KRED); fprintf (stderr,"Monitoring Source Audio when carrier present and No Sync Detected.\n"); fprintf (stderr," - May cause Pulse Audio Server to crash on some systems.\n"); + fprintf (stderr, "%s", KNRM); break; case 'N': @@ -786,6 +867,25 @@ main (int argc, char **argv) fprintf (stderr,"Logging MBE Payload to console\n"); break; + case 'T': + opts.dmr_stereo = 1; //just the end user option + state.dmr_stereo = 1; //this values toggles on and off depending on voice or data handling + opts.pulse_digi_rate_out = 24000; + opts.pulse_digi_out_channels = 2; + fprintf (stderr, "%s", KRED); + fprintf (stderr,"Experimental DMR Stereo Sync and Functionality. WIP!\n"); + fprintf (stderr,"DMR Stereo will disable WAV and MBE file saving!\n"); + fprintf (stderr,"Also consider using -F if playback is too choppy!\n"); + fprintf (stderr, "%s", KNRM); + break; + + case 'F': + opts.aggressive_framesync = 0; + fprintf (stderr, "%s", KRED); + fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n"); + fprintf (stderr, "%s", KNRM); + break; + case 'z': sscanf (optarg, "%d", &opts.scoperate); opts.errorbars = 0; @@ -830,13 +930,17 @@ main (int argc, char **argv) { fprintf (stderr,"Setting audio out gain to %f\n", opts.audio_gain); state.aout_gain = opts.audio_gain; + state.aout_gainR = opts.audio_gain; } break; case 'n': opts.reset_state = 1; + fprintf (stderr, "%s", KRED); fprintf (stderr,"Enabling Automatic Reset of P25 states\n"); - fprintf (stderr," -Helps with multiple signal type decoding\n"); - fprintf (stderr," -(WiP! May cause slow memory leak)\n"); + //fprintf (stderr," -Helps with multiple signal type decoding\n"); + //fprintf (stderr," -(WiP! May cause slow memory leak)\n"); + fprintf (stderr," -(Disabled until memory leak issues can be resolved!)\n"); + fprintf (stderr, "%s", KNRM); break; case 'w': strncpy(opts.wav_out_file, optarg, 1023); @@ -866,7 +970,7 @@ main (int argc, char **argv) opts.frame_dmr = 1; opts.frame_dpmr = 0; opts.frame_provoice = 0; - sprintf (opts.output_name, "Default Channel"); + sprintf (opts.output_name, "Auto Detect"); } else if (optarg[0] == 'd') { @@ -889,7 +993,7 @@ main (int argc, char **argv) opts.frame_nxdn48 = 0; opts.frame_nxdn96 = 0; opts.frame_dmr = 0; - opts.frame_dpmr = 0; //borrow from LEH + opts.frame_dpmr = 0; opts.frame_provoice = 0; sprintf (opts.output_name, "X2-TDMA"); fprintf (stderr,"Decoding only X2-TDMA frames.\n"); @@ -902,7 +1006,7 @@ main (int argc, char **argv) opts.frame_nxdn48 = 0; opts.frame_nxdn96 = 0; opts.frame_dmr = 0; - opts.frame_dpmr = 0; //borrow from LEH + opts.frame_dpmr = 0; opts.frame_provoice = 1; state.samplesPerSymbol = 5; state.symbolCenter = 2; @@ -911,8 +1015,7 @@ main (int argc, char **argv) opts.mod_gfsk = 1; state.rf_mod = 2; sprintf (opts.output_name, "ProVoice"); - //fprintf (stderr,"Setting symbol rate to 9600 / second\n"); - //fprintf (stderr,"Enabling only GFSK modulation optimizations.\n"); + fprintf (stderr,"Setting symbol rate to 9600 / second\n"); fprintf (stderr,"Decoding only ProVoice frames.\n"); } else if (optarg[0] == '1') @@ -925,9 +1028,9 @@ main (int argc, char **argv) opts.frame_dmr = 0; opts.frame_dpmr = 0; opts.frame_provoice = 0; - opts.mod_gfsk = 0; opts.mod_c4fm = 1; opts.mod_qpsk = 0; + opts.mod_gfsk = 0; state.rf_mod = 0; // sprintf (opts.output_name, "P25P1"); fprintf (stderr,"Decoding only P25 Phase 1 frames.\n"); @@ -942,6 +1045,7 @@ main (int argc, char **argv) opts.frame_dmr = 0; opts.frame_dpmr = 0; opts.frame_provoice = 0; + opts.frame_ysf = 0; state.samplesPerSymbol = 20; state.symbolCenter = 10; opts.mod_c4fm = 1; @@ -951,9 +1055,30 @@ main (int argc, char **argv) sprintf (opts.output_name, "NXDN48"); //opts.symboltiming = 2400; //NXDN48 uses 2400 symbol rate fprintf (stderr,"Setting symbol rate to 2400 / second\n"); - //fprintf (stderr,"Enabling only C4FM modulation optimizations.\n"); fprintf (stderr,"Decoding only NXDN 4800 baud frames.\n"); } + else if (optarg[0] == 'y') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_dpmr = 0; + opts.frame_provoice = 0; + opts.frame_ysf = 1; + state.samplesPerSymbol = 10; + //state.symbolCenter = 10; + opts.mod_c4fm = 1; + opts.mod_qpsk = 0; + opts.mod_gfsk = 0; + state.rf_mod = 0; + sprintf (opts.output_name, "YSF"); + //opts.symboltiming = 2400; //NXDN48 uses 2400 symbol rate + fprintf (stderr,"Setting symbol rate to 2400 / second\n"); + fprintf (stderr,"Decoding only YSF frames.\nNot working yet!\n"); + } else if (optarg[0] == 'n') { opts.frame_dstar = 0; @@ -969,7 +1094,6 @@ main (int argc, char **argv) opts.mod_gfsk = 0; state.rf_mod = 0; sprintf (opts.output_name, "NXDN96"); - //fprintf (stderr,"Enabling only C4FM modulation optimizations.\n"); fprintf (stderr,"Decoding only NXDN 9600 baud frames.\n"); } else if (optarg[0] == 'r') @@ -986,13 +1110,8 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; // state.rf_mod = 0; // - //opts.pulse_raw_rate_out = 24000; //doing tests with 2 channels at 24000 for 48000 audio default in pulse - //opts.pulse_digi_rate_out = 24000; //need to copy this to rtl type in and change rate out to 8000 - //opts.pulse_raw_out_channels = 2; - //opts.pulse_digi_out_channels = 2; //2 sprintf (opts.output_name, "DMR/MOTOTRBO"); - //sprintf (opts.output_name, "DMR/MOTOTRBO Left"); - fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); + //fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); fprintf (stderr,"Decoding only DMR/MOTOTRBO frames.\n"); } else if (optarg[0] == 'm') @@ -1005,6 +1124,7 @@ main (int argc, char **argv) opts.frame_dmr = 0; opts.frame_provoice = 0; opts.frame_dpmr = 1; + opts.frame_ysf = 0; //testing with NXDN48 parameters state.samplesPerSymbol = 20; //same as NXDN48 - 20 state.symbolCenter = 10; //same as NXDN48 - 10 opts.mod_c4fm = 1; @@ -1013,11 +1133,10 @@ main (int argc, char **argv) state.rf_mod = 0; sprintf (opts.output_name, "dPMR"); fprintf(stderr, "Notice: dPMR cannot autodetect polarity. \n Use -xd option if Inverted Signal expected.\n"); - //fprintf(stderr, "Enabling only C4FM modulation optimizations.\n"); fprintf(stderr, "Decoding only dPMR frames.\n"); } break; - //don't mess with the modulations, doesn't really do anything anyways + //don't mess with the modulations, doesn't really do anything meaningful anyways case 'm': if (optarg[0] == 'a') { @@ -1127,7 +1246,6 @@ main (int argc, char **argv) if (opts.use_ncurses_terminal == 1) { ncursesOpen(); - //ncursesPrinter(&opts, &state); } if (opts.resume > 0) @@ -1165,6 +1283,7 @@ main (int argc, char **argv) { opts.split = 1; opts.playoffset = 0; + opts.playoffsetR = 0; opts.delay = 0; if (strlen(opts.wav_out_file) > 0) { @@ -1179,6 +1298,7 @@ main (int argc, char **argv) { opts.split = 1; opts.playoffset = 0; + opts.playoffsetR = 0; opts.delay = 0; if (strlen(opts.wav_out_file) > 0) { @@ -1191,13 +1311,14 @@ main (int argc, char **argv) openAudioInDevice (&opts); - fprintf (stderr,"Press CTRL + C twice to close.\n"); //Kindly remind user to double tap CTRL + C + fprintf (stderr,"Press CTRL + C twice to close.\n"); } else { opts.split = 0; - opts.playoffset = 25; // 38 + opts.playoffset = 25; // 38 + opts.playoffsetR = 25; // 38 opts.delay = 0; openAudioInDevice (&opts); //disabled all four instances of openAudio devices, in and out for now opts.audio_out_fd = opts.audio_in_fd; @@ -1205,7 +1326,8 @@ main (int argc, char **argv) if (opts.playfiles == 1) { - opts.pulse_digi_rate_out = 8000; //need set to 8000 for amb/imb playback + //need set to 8000/1 for amb/imb playback, upsampling seems to cause random crackling + opts.pulse_digi_rate_out = 8000; opts.pulse_digi_out_channels = 1; openPulseOutput(&opts); //need to open it up for output playMbeFiles (&opts, &state, argc, argv); @@ -1214,8 +1336,8 @@ main (int argc, char **argv) else { liveScanner (&opts, &state); - } + if (opts.use_ncurses_terminal == 1){ //ncursesClose (); } diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index bfc5883..0c64119 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -126,44 +126,78 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } else { - mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); -#ifdef AMBE_PACKET_OUT - - for(i=0; i<49; i++) { - ambe_d_str[i] = ambe_d[i] + '0'; + //stereo slots and slot 0 (left slot) + if (state->currentslot == 0 && opts->dmr_stereo == 1) + { + mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); } - ambe_d_str[49] = '\0'; - // print binary string - fprintf (stderr, "\n?\t?\t%s\t", ambe_d_str); - // print error data - fprintf (stderr, "E1: %d; E2: %d; S: %s", state->errs, state->errs2, state->err_str);} -#endif - if (opts->mbe_out_f != NULL) + //stereo slots and slot 1 (right slot) + if (state->currentslot == 1 && opts->dmr_stereo == 1) + { + mbe_processAmbe3600x2450Framef (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR, ambe_fr, ambe_d, state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2, opts->uvquality); + //just put this in here for troubleshooting for now + if (opts->mbe_out_f != NULL) { saveAmbe2450Data (opts, state, ambe_d); } + } + if (opts->dmr_stereo == 0) + { + mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, ambe_d); + } + } + + } if (opts->errorbars == 1) { //state->err_buf = state->err_str; //make comy to compare, and only print when comparison differs?? THIS HERE HERE //strncpy (state->err_buf, state->err_str, sizeof(state->err_str)); //is this the correct placement for this? want it just before err_str is set? - fprintf (stderr, "%s", state->err_str); //this the actual error 'bar' ==== printer, find way to keep this entire string from printing constantly unless err_str changes + //fprintf (stderr, "%s", state->err_str); //this the actual error 'bar' ==== printer, find way to keep this entire string from printing constantly unless err_str changes //fprintf (stderr, "%s", state->err_buf); } state->debug_audio_errors += state->errs2; - - processAudio (opts, state); - if (opts->wav_out_f != NULL) - { - writeSynthesizedVoice (opts, state); - } - - if (opts->audio_out == 1) + state->debug_audio_errorsR += state->errs2R; + if (opts->dmr_stereo == 1 && state->currentslot == 0) + { + processAudio (opts, state); + if (opts->audio_out == 1) { playSynthesizedVoice (opts, state); } + } + if (opts->dmr_stereo == 1 && state->currentslot == 1) + { + processAudioR (opts, state); + if (opts->audio_out == 1) + { + playSynthesizedVoiceR (opts, state); + } + } + if (opts->dmr_stereo == 0) + { + processAudio (opts, state); + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } + } + if (opts->wav_out_f != NULL && opts->dmr_stereo == 0) + { + writeSynthesizedVoice (opts, state); + } + /* + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } + */ } /* This function decipher data */ diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 0325817..733c829 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -30,19 +30,20 @@ int reset = 0; char c; //getch key -int tg; //last tg +int tg; +int tgR; int tgn; -int rd; //last rid -int rn; //last ran -int nc; //nac -int src; //last rid? double? -int lls = -1; //last last sync type -int dcc = -1; //initialize with 0 to prevent core dump +int rd; +int rdR; +int rn; +int nc; +int src; +int lls = -1; +int dcc = -1; int i = 0; -char * s0last = " "; -char * s1last = " "; char versionstr[25]; -unsigned long long int call_matrix[33][6]; //0 - sync type; 1 - tg/ran; 2 - rid; 3 - slot; 4 - cc; 5 - time(NULL) ; +unsigned long long int call_matrix[33][6]; + char * FM_bannerN[9] = { " CTRL + C twice to exit", " ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗", @@ -54,25 +55,25 @@ char * FM_bannerN[9] = { "https://github.com/lwvmobile/dsd-fme/tree/pulseaudio " }; -char * SyncTypes[30] = { +char * SyncTypes[36] = { "+P25P1", "-P25P1", "+X2TDMA DATA", "-X2TDMA DATA", "+X2TDMA VOICE", "-X2TDMA VOICE", - "+DSTARC", + "+DSTAR", "-DSTAR", - "+NXDN VOICE", //8 - "-NXDN VOICE", //9 - "+DMR DATA", //10 - "-DMR DATA", //11 - "+DMR VOICE", //12 - "-DMR VOICE", //13 - "+PROVOICE", //14 - "-PROVOICE", //15 - "+NXDN DATA", //16 - "-NXDN DATA", //17 + "+NXDN VOICE", + "-NXDN VOICE", + "+DMR DATA", + "-DMR DATA", + "+DMR VOICE", + "-DMR VOICE", + "+PROVOICE", + "-PROVOICE", + "+NXDN DATA", + "-NXDN DATA", "+DSTAR HD", "-DSTAR HD", "+dPMR", @@ -82,7 +83,35 @@ char * SyncTypes[30] = { "-dPMR", "-dPMR", "-dPMR", - "-dPMR" + "-dPMR", + "+NXDN (sync only)", + "-NXDN (sync only)", + "+YSF", + "-YSF", + "DMR MS VOICE", + "DMR MS DATA", + "DMR RC DATA" +}; + +char * DMRBusrtTypes[18] = { + "PI Header ", + "VOICE LC HDR ", + "TLC ", + "CSBK ", + "MBC Header ", + "MBC Cont ", + "DATA Header ", + "RATE 1/2 DATA ", + "RATE 3/4 DATA ", + "Slot Idle ", + "Rate 1 DATA ", + "ERR ", //These values for ERR may be Reserved for use in future? + "ERR ", + "ERR ", + "ERR ", + "ERR ", + "Voice ", //Using 16 for Voice since its higher than possible value? + "INITIAL " //17 is assigned on start up }; @@ -116,48 +145,139 @@ void ncursesOpen () noecho(); cbreak(); - //fprintf (stderr, "Opening NCurses Terminal. \n"); - } void ncursesPrinter (dsd_opts * opts, dsd_state * state) { int level; - - //level = (int) state->max / 164; level = 0; //start each cycle with 0 - erase(); - //disabling until wide support can be built for LM, etc. $(ncursesw5-config --cflags --libs) - printw ("%s \n", FM_bannerN[0]); //top line in white - attron(COLOR_PAIR(4)); - for (short int i = 1; i < 7; i++) //following lines in cyan - { - printw("%s \n", FM_bannerN[i]); - } - attroff(COLOR_PAIR(4)); - printw ("--Build Info------------------------------------------------------------------\n"); - printw ("| %s \n", FM_bannerN[7]); //http link - printw ("| Digital Speech Decoder: Florida Man Edition\n"); - printw ("| Github Build Version: %s \n", GIT_TAG); - printw ("| mbelib version %s\n", versionstr); - //printw ("| Press CTRL+C twice to exit\n"); - printw ("------------------------------------------------------------------------------\n"); + //Variable reset/set section + + //carrier reset if (state->carrier == 0) //reset these to 0 when no carrier { - state->payload_algid = 0; - state->payload_keyid = 0; + state->payload_algid = 0; + state->payload_keyid = 0; + state->payload_keyidR = 0; + state->payload_algidR = 0; //state->payload_mfid = 0; - state->payload_mi = 0; + state->payload_mi = 0; + state->payload_miR = 0; state->nxdn_key = 0; state->nxdn_cipher_type = 0; - + //memset(state->dstarradioheader, 0, 41); sprintf(state->dmr_branding, " "); } - if ( (lls == 14 || lls == 15) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1) //honestly have no idea how to do this for pV, just going time based? only update on carrier == 1. + //set lls sync types + if (state->synctype >= 0 && state->synctype < 35) //not sure if this will be okay + { + lls = state->synctype; + } + + //reset DMR alias block and embedded gps if burst type is not 16 or carrier drop + if (state->dmrburstL != 16 || state->carrier == 0) + { + for (short i = 0; i < 6; i++) + { + sprintf (state->dmr_callsign[0][i], ""); + } + } + if (state->dmrburstR != 16 || state->carrier == 0) + { + for (short i = 0; i < 6; i++) + { + sprintf (state->dmr_callsign[1][i], ""); + } + } + + //reset DMR LRRP when call is active on current slot if burst type is not data or carrier drop + if (state->dmrburstL == 16 || state->carrier == 0) + { + for (short i = 0; i < 6; i++) + { + sprintf (state->dmr_lrrp[0][i], ""); + } + } + if (state->dmrburstR == 16 || state->carrier == 0) + { + for (short i = 0; i < 6; i++) + { + sprintf (state->dmr_lrrp[1][i], ""); + } + } + + //NXDN + if (state->nxdn_last_rid > 0 && state->nxdn_last_rid != src); + { + src = state->nxdn_last_rid; + } + if (state->nxdn_last_ran > -1 && state->nxdn_last_ran != rn); + { + rn = state->nxdn_last_ran; + } + if (state->nxdn_last_tg > 0 && state->nxdn_last_tg != tgn); + { + tgn = state->nxdn_last_tg; + } + + //DMR CC + if (state->color_code_ok && state->dmr_color_code != -1 && (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33) ) + { + dcc = state->dmr_color_code; + } + + //DMR SRC + if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) ) + { + if (state->dmrburstL == 16 && state->lastsrc > 0) //state->currentslot == 0 && + { + rd = state->lastsrc; + } + + if (state->dmrburstR == 16 && state->lastsrcR > 0) //state->currentslot == 1 && + { + rdR = state->lastsrcR; + } + //move to seperate P25 version plz + opts->p25enc = 0; + } + + //DMR TG + if ( (lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32) ) + { + if (state->dmrburstL == 16 && state->lasttg > 0) //state->currentslot == 0 && + { + tg = state->lasttg; + } + + if (state->dmrburstR == 16 && state->lastsrcR > 0) //state->currentslot == 1 && + { + tgR = state->lasttgR; + } + opts->p25enc = 0; + } + + //P25 + if (state->nac > 0) + { + nc = state->nac; + } + if ( state->lasttg > 0 && (lls == 0 || lls == 1) ) + { + tg = state->lasttg; + } + if ( state->lastsrc > 0 && (lls == 0 || lls == 1) ) + { + rd = state->lastsrc; + } + + //Call History Matrix Shuffling + //ProVoice + if ( (lls == 14 || lls == 15) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1) { for (short int k = 0; k < 9; k++) { @@ -175,12 +295,33 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[9][3] = 1; call_matrix[9][4] = 1; call_matrix[9][5] = time(NULL); - //nowN = time(NULL); + } - //if ( (state->nxdn_last_rid != src && src > 0) || (state->nxdn_last_ran != rn && rn > 0) ) //find condition to make this work well, probably if last != local last variables - //if ( (call_matrix[9][2] != src && src > 0) || (call_matrix[9][1] != rn && rn > 0) ) //NXDN working well now with this, updates immediately and only once - if ( call_matrix[9][2] != src && src > 0 && rn > -1 ) //NXDN working well now with this, updates immediately and only once + //D-STAR, work on adding the headers later + if ( (lls == 6 || lls == 7 || lls == 18 || lls == 19) && (time(NULL) - call_matrix[9][5] > 5) && state->carrier == 1) + { + for (short int k = 0; k < 9; k++) + { + call_matrix[k][0] = call_matrix[k+1][0]; + call_matrix[k][1] = call_matrix[k+1][1]; + call_matrix[k][2] = call_matrix[k+1][2]; + call_matrix[k][3] = call_matrix[k+1][3]; + call_matrix[k][4] = call_matrix[k+1][4]; + call_matrix[k][5] = call_matrix[k+1][5]; + } + + call_matrix[9][0] = lls; + call_matrix[9][1] = 1; + call_matrix[9][2] = 1; + call_matrix[9][3] = 1; + call_matrix[9][4] = 1; + call_matrix[9][5] = time(NULL); + + } + + //NXDN + if ( call_matrix[9][2] != src && src > 0 && rn > -1 ) { for (short int k = 0; k < 9; k++) { @@ -200,17 +341,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } - //if (state->dmr_color_code != dcc && (lls == 11 || lls == 13 || lls == 10 || lls == 12) ) //DMR Voice + last two is data - //if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR - if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 12 || lls == 13) ) //DMR, needs work + //DMR MS + if ( call_matrix[9][2] != rd && (lls == 32 || lls == 33 || lls == 34) ) { - //reset amateur signs on radio id change - for (short i = 0; i < 5; i++) - { - sprintf (state->dmr_callsign[i], ""); - } - //dcc = state->dmr_color_code; - for (short int k = 0; k < 9; k++) + + for (short int k = 0; k < 10; k++) { call_matrix[k][0] = call_matrix[k+1][0]; call_matrix[k][1] = call_matrix[k+1][1]; @@ -223,14 +358,60 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[9][0] = lls; call_matrix[9][1] = tg; call_matrix[9][2] = rd; - call_matrix[9][3] = 0; + call_matrix[9][3] = 1; //hard set slot number call_matrix[9][4] = dcc; call_matrix[9][5] = time(NULL); - //i++; + } - //if ( (lls == 0 || lls == 1) && state->lastsrc != rd && state->lastsrc > 0) //find condition to make this work well, probably if last != local last variables - if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0) //P25 + //DMR BS Slot 1 - matrix 0-4 + if ( call_matrix[4][2] != rd && (lls == 12 || lls == 13 || lls == 10 || lls == 11) ) + { + + for (short int k = 0; k < 4; k++) + { + call_matrix[k][0] = call_matrix[k+1][0]; + call_matrix[k][1] = call_matrix[k+1][1]; + call_matrix[k][2] = call_matrix[k+1][2]; + call_matrix[k][3] = call_matrix[k+1][3]; + call_matrix[k][4] = call_matrix[k+1][4]; + call_matrix[k][5] = call_matrix[k+1][5]; + } + + call_matrix[4][0] = lls; + call_matrix[4][1] = tg; + call_matrix[4][2] = rd; + call_matrix[4][3] = 1; //hard set slot number + call_matrix[4][4] = dcc; + call_matrix[4][5] = time(NULL); + + } + + //DMR BS Slot 2 - matrix 5-9 + if ( call_matrix[9][2] != rdR && (lls == 12 || lls == 13 || lls == 10 || lls == 11) ) + { + + for (short int k = 5; k < 9; k++) + { + call_matrix[k][0] = call_matrix[k+1][0]; + call_matrix[k][1] = call_matrix[k+1][1]; + call_matrix[k][2] = call_matrix[k+1][2]; + call_matrix[k][3] = call_matrix[k+1][3]; + call_matrix[k][4] = call_matrix[k+1][4]; + call_matrix[k][5] = call_matrix[k+1][5]; + } + + call_matrix[9][0] = lls; + call_matrix[9][1] = tgR; + call_matrix[9][2] = rdR; + call_matrix[9][3] = 2; //hard set slot number + call_matrix[9][4] = dcc; + call_matrix[9][5] = time(NULL); + + } + + //P25 + if ( (lls == 0 || lls == 1) && call_matrix[9][2] != rd && nc > 0 && tg > 0) { for (short int k = 0; k < 9; k++) { @@ -248,19 +429,34 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[9][3] = 0; call_matrix[9][4] = nc; call_matrix[9][5] = time(NULL); - //i++; + } - //printw ("Time: "); - //printw ("%s \n", getTimeN()); + + //Start Printing Section + erase(); + printw ("%s \n", FM_bannerN[0]); //top line in white + attron(COLOR_PAIR(4)); + for (short int i = 1; i < 7; i++) //following lines in cyan + { + printw("%s \n", FM_bannerN[i]); + } + attroff(COLOR_PAIR(4)); + printw ("--Build Info------------------------------------------------------------------\n"); + printw ("| %s \n", FM_bannerN[7]); //http link + printw ("| Digital Speech Decoder: Florida Man Edition\n"); + printw ("| Github Build Version: %s \n", GIT_TAG); + printw ("| mbelib version %s\n", versionstr); + //printw ("| Press CTRL+C twice to exit\n"); + printw ("------------------------------------------------------------------------------\n"); attron(COLOR_PAIR(4)); printw ("--Input Output----------------------------------------------------------------\n"); if (opts->audio_in_type == 0) { - printw ("| Pulse Audio Input [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); + printw ("| Pulse Audio Input: [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); } if (opts->audio_in_type == 1) { - printw ("| STDIN - Input\n"); + printw ("| STDIN Standard Input: - \n"); } if (opts->audio_in_type == 3) { @@ -273,17 +469,17 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } if (opts->audio_out_type == 0) { - printw ("| Pulse Audio Output [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels); + printw ("| Pulse Audio Output: [%i] kHz [%i] Channel\n", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels); } if (opts->monitor_input_audio == 1) { - printw ("| Monitoring Source Audio when carrier present and No Sync Detected\n"); + printw ("| Monitoring Source Audio when Carrier Present and No Sync Detected\n"); } - if (opts->mbe_out_dir[0] != 0) + if (opts->mbe_out_dir[0] != 0 && opts->dmr_stereo == 0) { printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir); } - if (opts->wav_out_file[0] != 0) + if (opts->wav_out_file[0] != 0 && opts->dmr_stereo == 0) { printw ("| Appending Audio WAV to file %s\n", opts->wav_out_file); } @@ -302,77 +498,52 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) reset = 0; } - printw ("--Audio Decode----------------------------------------------------------------\n"); + printw ("| Decoding: [%s] \n", opts->output_name); printw ("| In Level: [%3i%%] \n", level); - printw ("| Voice Error: [%i][%i] \n| Error Bars: [%s] \n", state->errs, state->errs2, state->err_str); // - //printw ("| Carrier = %i\n", state->carrier); + if (opts->dmr_stereo == 0) + { + printw ("| Voice Error: [%i][%i] \n", state->errs, state->errs2); + } + + if (opts->dmr_stereo == 1) + { + printw ("| Voice ErrS1: [%i][%i] \n", state->errs, state->errs2); + printw ("| Voice ErrS2: [%i][%i] \n", state->errsR, state->errs2R); + } printw ("------------------------------------------------------------------------------\n"); - printw ("--Call Info-------------------------------------------------------------------\n"); - //NXDN Ciper Types - //switch(CipherType) - //{ - // case 0: Ptr = ""; break; /* Non-ciphered mode / clear call */ - // case 1: Ptr = "Scrambler"; break; - // case 2: Ptr = "DES"; break; - // case 3: Ptr = "AES"; break; - // default: Ptr = "Unknown Cipher Type"; break; - //} - - if (state->lastsynctype != -1) //not sure if this will be okay + //DSTAR...what a pain... + if (lls == 6 || lls == 7 || lls == 18 || lls == 19) { - lls = state->lastsynctype; - } - if (state->nxdn_last_rid > 0 && state->nxdn_last_rid != src); - { - src = state->nxdn_last_rid; - } - if (state->nxdn_last_ran > -1 && state->nxdn_last_ran != rn); - { - rn = state->nxdn_last_ran; - } - if (state->nxdn_last_tg > 0 && state->nxdn_last_tg != tgn); - { - tgn = state->nxdn_last_tg; + if (state->dstarradioheader[3] != 0) // + { + printw ("| RPT 2: [%c%c%c%c%c%c%c%c] ", state->dstarradioheader[3], state->dstarradioheader[4], + state->dstarradioheader[5], state->dstarradioheader[6], state->dstarradioheader[7], state->dstarradioheader[8], + state->dstarradioheader[9], state->dstarradioheader[10]); + printw ("RPT 1: [%c%c%c%c%c%c%c%c] \n| ", state->dstarradioheader[11], state->dstarradioheader[12], + state->dstarradioheader[13], state->dstarradioheader[14], state->dstarradioheader[15], state->dstarradioheader[16], + state->dstarradioheader[17], state->dstarradioheader[18]); + printw ("YOUR: [%c%c%c%c%c%c%c%c] ", state->dstarradioheader[19], state->dstarradioheader[20], + state->dstarradioheader[21], state->dstarradioheader[22], state->dstarradioheader[23], state->dstarradioheader[24], + state->dstarradioheader[25], state->dstarradioheader[26]); + printw ("MY: [%c%c%c%c%c%c%c%c] [%c%c%c%c]\n", state->dstarradioheader[27], + state->dstarradioheader[28], state->dstarradioheader[29], state->dstarradioheader[30], state->dstarradioheader[31], + state->dstarradioheader[32], state->dstarradioheader[33], state->dstarradioheader[34], state->dstarradioheader[35], + state->dstarradioheader[36], state->dstarradioheader[37], state->dstarradioheader[38]); + } } - //if (state->dmr_color_code > 0 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data? - //if (state->color_code > -1 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data? - if (state->color_code_ok && (lls == 12 || lls == 13) ) //DMR, needs work - - { - dcc = state->dmr_color_code; - //dcc = state->color_code; - } - - if (state->lastsrc > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1 - { - rd = state->lastsrc; - opts->p25enc = 0; - } - - if (state->lasttg > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1 - { - tg = state->lasttg; - opts->p25enc = 0; - } - - //if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //change this to NXDN syncs later on + //NXDN if (lls == 8 || lls == 9 || lls == 16 || lls == 17) { printw ("| RAN: [%2d] ", rn); printw ("TID: [%4d] ", tgn); - //printw ("| RID: [%d] \n", src); printw ("RID: [%4d] \n| ALG: [0x%02X] KEY [0x%02X] ", src, state->nxdn_cipher_type, state->nxdn_key); if (state->carrier == 1) { printw("%s ", state->nxdn_call_type); - //attron(COLOR_PAIR(4)); - //printw ("No Encryption "); - //attroff(COLOR_PAIR(4)); - //attron(COLOR_PAIR(3)); } if (state->nxdn_cipher_type == 0x1 && state->carrier == 1) { @@ -404,31 +575,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } //printw("%s ", state->nxdn_call_type); printw("\n"); - - } - //printw ("Error?: [%i] [%i] \n", state->errs, state->errs2); //what are these? - /* //wasn't we already doing this twice - if (state->lasttg > 0 && state->lastsrc > 0) + //P25 + if (lls == 0 || lls == 1) { - tg = state->lasttg; - rd = state->lastsrc; - } - */ - if (state->nac > 0) - { - nc = state->nac; - } - if ((lls == 0 || lls == 1)) //1 for P25 P1 Audio - { - //printw("| TID:[%i] | RID:[%i] \n", tg, rd); - //printw("| NAC: [0x%X] \n", nc); printw("| TID:[%8i] RID:[%8i] ", tg, rd); printw("NAC: [0x%3X] \n", nc); printw("| ALG:[0x%02X] ", state->payload_algid); printw(" KEY:[0x%04X] ", state->payload_keyid); - printw(" MFID: [0x%02X] ", state->payload_mfid); //no way of knowing if this is accurate info yet + printw(" MFID: [0x%02X] ", state->payload_mfid); //no way of knowing if this is accurate info yet if (state->payload_algid != 0x80 && state->payload_algid != 0x0 && state->carrier == 1) { attron(COLOR_PAIR(2)); @@ -437,182 +593,222 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } printw("\n"); - //printw("| System Type: %s \n", ALGIDS[state->payload_keyid] ); - } - //if (state->lastsynctype == 12 || state->lastsynctype == 13) //DMR Voice Types - if (lls == 12 || lls == 13) //DMR Voice Types - { - //printw ("| DCC: [%i] FID: [%02X]\n", dcc, state->dmr_fid); - //attron(COLOR_PAIR(3)); - printw ("| DCC: [%2i] FID: [%02X] SOP: [%02X] ", dcc, state->dmr_fid, state->dmr_so); - //if(state->payload_mi == 0 && state->dmr_so & 0x40) - if(state->payload_mi == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? - { - attron(COLOR_PAIR(5)); - printw ("**BP** "); - //printw ("0x%X", state->payload_algid); - attroff(COLOR_PAIR(5)); - attron(COLOR_PAIR(3)); - } - //if(state->payload_keyid > 0 && state->dmr_so & 0x40) - if(state->payload_keyid > 0 && (state->dmr_so & 0xCF) == 0x40) - { - attron(COLOR_PAIR(5)); - printw (" ALG: [0x%02X] KEY [0x%02X] MI [0x%08X]", state->payload_algid, state->payload_keyid, state->payload_mi); - //printw ("0x%X", state->payload_algid); - attroff(COLOR_PAIR(5)); - attron(COLOR_PAIR(3)); - } - //if(state->K > 0 && state->payload_keyid == 0 && state->dmr_so & 0x40) - if(state->K > 0 && (state->dmr_so & 0xCF) == 0x40) - { - attron(COLOR_PAIR(5)); - printw ("BPK [%3lld]", state->K); - attroff(COLOR_PAIR(5)); - attron(COLOR_PAIR(3)); - } - - printw("\n"); - printw ("| TID: [%8i] RID: [%8i]", tg, rd); - - if (1 == 1) //figure out what to put here later on for amateur call signs - { - printw (" ["); - for (short i = 0; i < 5; i++) - { - printw ("%s", state->dmr_callsign[i]); - } - printw ("]"); - } - //if(state->dmr_so & 0x80) //1000 0000 //prints emergency on some amateru DMR repeaters with 0x8E SOP code, need to investigate - if(state->dmr_so == 0x80) - { - attron(COLOR_PAIR(2)); - printw (" **Emergency** "); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - - //if(state->dmr_so & 0x40) //0100 0000 - if(state->dmr_so == 0x40) //0100 0000 - { - attron(COLOR_PAIR(2)); - printw (" **ENC** "); - //printw ("0x%X", state->payload_algid); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - if (state->K == 0) - { - //opts->p25enc = 1; //just testing for now - } - - } - - //if(state->dmr_so & 0x30) //0010 0000 - if(state->dmr_so == 0x30) //0010 0000 - { - attron(COLOR_PAIR(2)); - printw (" **Private Call** "); - attroff(COLOR_PAIR(2)); - attron(COLOR_PAIR(3)); - } - printw("\n"); - //printw ("%s ", state->slot0light); - printw ("| SLOT 1 "); - if (state->currentslot == 0) //find out how to tell when slot0 has voice - { - s0last = "Voice"; - //printw("Voice"); - } - printw ("%s ", s0last); - - //printw ("%s ", state->slot1light); - printw ("SLOT 2 "); - if (state->currentslot == 1) //find out how to tell when slot1 has voice - { - s1last = "Voice"; - //printw("Voice"); - } - printw ("%s \n", s1last); } - - //if (state->lastsynctype == 10 || state->lastsynctype == 11) //DMR Data Types - if (lls == 10 || lls == 11 ) //DMR Data Types + //DMR BS/MS Voice and Data Types + if ( lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33 || lls == 34) { - //printw ("| DCC: [%i]\n", dcc); - printw ("| DCC: [%2i] FID: [%02X] SOP: [%02X] \n", dcc, state->dmr_fid, state->dmr_so); - printw ("| TID: [%8i] RID: [%8i]", tg, rd); - - if (1 == 1) //figure out what to put here later on for amateur call signs + printw ("| "); + if (lls < 30) { - printw (" ["); - for (short i = 0; i < 5; i++) - { - printw ("%s", state->dmr_callsign[i]); - } - printw ("]"); + printw ("DMR BS - DCC: [%02i] ", dcc); } - //does this need to be in DATA type? - /* - if(state->dmr_so & 0x80) + else + { + printw ("DMR MS - DCC: [%02i] ", dcc); + } + + printw ("\n"); + //Slot 1 [0] + printw ("| SLOT 1 - "); + if (state->dmrburstL != 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0) { attron(COLOR_PAIR(2)); - printw (" **Emergency** "); + } + printw ("TGT: [%8i] SRC: [%8i] ", state->lasttg, state->lastsrc); + if (state->dmrburstL != 16 && state->carrier == 1 && state->lasttg > 0 && state->lastsrc > 0) + { attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } + printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fid, state->dmr_so); + printw ("%s ", DMRBusrtTypes[state->dmrburstL]); + printw ("\n"); + //printw ("| | "); //10 spaces + printw ("| V XTRA | "); //10 spaces + //Burger King + if(state->dmrburstL == 16 && state->payload_mi == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? + { + attron(COLOR_PAIR(5)); + printw (" **BP** "); + attroff(COLOR_PAIR(5)); + attron(COLOR_PAIR(3)); + } + //Point + if(state->dmrburstL == 16 && state->payload_mi == 0 && state->K > 0 && (state->dmr_so & 0xCF) == 0x40) + { + attron(COLOR_PAIR(1)); + printw ("BPK [%3lld] ", state->K); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + //ALG, KeyID, MI + if(state->dmrburstL == 16 && state->payload_keyid > 0 && (state->dmr_so & 0xCF) == 0x40) + { + attron(COLOR_PAIR(1)); + printw ("ALG: [0x%02X] KEY: [0x%02X] MI: [0x%08X]", state->payload_algid, state->payload_keyid, state->payload_mi); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } - if(state->dmr_so & 0x40) + if(state->dmrburstL == 16 && state->dmr_so == 0x40) //0100 0000 { attron(COLOR_PAIR(2)); printw (" **ENC** "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } - - if(state->dmr_so & 0x30) + if(state->dmrburstL == 16 && state->dmr_so == 0x80) + { + attron(COLOR_PAIR(2)); + printw (" **Emergency** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstL == 16 && state->dmr_so == 0x30) //0010 0000 { attron(COLOR_PAIR(2)); printw (" **Private Call** "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } - */ - printw("\n"); + printw ("\n"); + //Alias Blocks and Embedded GPS + //printw ("| | "); //10 spaces + printw ("| D XTRA | "); + if(state->dmrburstL == 16) //only during call + { + attron(COLOR_PAIR(5)); + for (short i = 0; i < 5; i++) + { + printw ("%s", state->dmr_callsign[0][i]); + } + //Embedded GPS (not LRRP) + printw ("%s", state->dmr_callsign[0][5] ); + attroff(COLOR_PAIR(5)); + if (state->carrier == 1) + { + attron(COLOR_PAIR(3)); + } - //printw ("%s ", state->slot0light); - printw ("| SLOT 1 "); - if (state->currentslot == 0) //find out how to tell when slot0 has voice - { - s0last = "Data "; - if (strcmp (state->fsubtype, " Slot idle ") == 0) + //LRRP + if(state->dmrburstL != 16) //only during data { - s0last = "Idle "; + attron(COLOR_PAIR(5)); + for (short i = 0; i < 5; i++) + { + printw ("%s", state->dmr_lrrp[0][i]); + } + attroff(COLOR_PAIR(5)); + if (state->carrier == 1) + { + attron(COLOR_PAIR(3)); + } } } - printw ("%s ", s0last); - //printw ("%s ", state->slot1light); - printw ("SLOT 2 "); - if (state->currentslot == 1) //find out how to tell when slot1 has voice + printw ("\n"); + + //Slot 2 [1] + if (lls < 30){ //Don't print on MS mode + printw ("| SLOT 2 - "); + if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) { - s1last = "Data "; - if (strcmp (state->fsubtype, " Slot idle ") == 0) + attron(COLOR_PAIR(2)); + } + printw ("TGT: [%8i] SRC: [%8i] ", state->lasttgR, state->lastsrcR); + if (state->dmrburstR != 16 && state->carrier == 1 && state->lasttgR > 0 && state->lastsrcR > 0) + { + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + printw ("FID: [%02X] SVC: [%02X] ", state->dmr_fidR, state->dmr_soR); + printw ("%s ", DMRBusrtTypes[state->dmrburstR]); + printw ("\n"); + //printw ("| | "); //12 spaces + printw ("| V XTRA | "); //10 spaces + + //Burger King 2 + if(state->dmrburstR == 16 && state->payload_miR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask? + { + attron(COLOR_PAIR(5)); + printw (" **BP** "); + attroff(COLOR_PAIR(5)); + attron(COLOR_PAIR(3)); + } + //Point 2 + if(state->dmrburstR == 16 && state->payload_miR == 0 && state->K > 0 && (state->dmr_soR & 0xCF) == 0x40) + { + attron(COLOR_PAIR(1)); + printw ("BPK [%3lld] ", state->K); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + //ALG, KeyID, MI 2 + if(state->dmrburstR == 16 && state->payload_keyidR > 0 && (state->dmr_soR & 0xCF) == 0x40) + { + attron(COLOR_PAIR(1)); + printw ("ALG: [0x%02X] KEY: [0x%02X] MI: [0x%08X]", state->payload_algidR, state->payload_keyidR, state->payload_miR); + attroff(COLOR_PAIR(1)); + attron(COLOR_PAIR(3)); + } + //Call Types, may switch to the more robust version later? + if(state->dmrburstR == 16 && state->dmr_soR == 0x40) //0100 0000 + { + attron(COLOR_PAIR(2)); + printw (" **ENC** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstR == 16 && state->dmr_soR == 0x80) + { + attron(COLOR_PAIR(2)); + printw (" **Emergency** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + if(state->dmrburstR == 16 && state->dmr_soR == 0x30) //0010 0000 + { + attron(COLOR_PAIR(2)); + printw (" **Private Call** "); + attroff(COLOR_PAIR(2)); + attron(COLOR_PAIR(3)); + } + printw ("\n"); + //Alias Blocks and Embedded GPS + //printw ("| | "); + printw ("| D XTRA | "); + if(state->dmrburstR == 16) //only during call + { + attron(COLOR_PAIR(5)); + for (short i = 0; i < 5; i++) { - s1last = "Idle "; + printw ("%s", state->dmr_callsign[1][i]); + } + //Embedded GPS (not LRRP) + printw ("%s", state->dmr_callsign[1][5] ); + attroff(COLOR_PAIR(5)); + if (state->carrier == 1) + { + attron(COLOR_PAIR(3)); } } - printw ("%s \n", s1last); - /* - if (state->dmr_lrrp[3] != NULL) + //LRRP + if(state->dmrburstR != 16) //only during data { - printw ("| LRRP -"); - printw (" %s", state->dmr_lrrp[3]); - printw (" %s", state->dmr_lrrp[1]); - printw (" %s\n", state->dmr_lrrp[2]); + attron(COLOR_PAIR(5)); + for (short i = 0; i < 5; i++) + { + printw ("%s", state->dmr_lrrp[1][i]); + } + attroff(COLOR_PAIR(5)); + if (state->carrier == 1) + { + attron(COLOR_PAIR(3)); + } } - */ - } + printw ("\n"); + } // end if not MS + } //end DMR BS Types //dPMR if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) @@ -621,97 +817,73 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) printw ("TID: [%s] RID: [%s] \n", state->dpmr_target_id, state->dpmr_caller_id); } - if (lls != -1) //is there a synctype 0? + if (lls == 6 || lls == 7 || lls == 18 || lls == 19 || lls == 14 || lls == 15) { printw ("| %s ", SyncTypes[lls]); //printw ("%s", state->dmr_branding); printw ("\n"); } + //fence bottom printw ("------------------------------------------------------------------------------\n"); //colors off if (state->carrier == 1){ //same as above attroff(COLOR_PAIR(3)); } - //if (state->carrier == 0){ //same as above - //attroff(COLOR_PAIR(1)); - //} attron(COLOR_PAIR(4)); //cyan for history - //add other interesting info to put here - //make Call_Matrix - //0 - sync type; 1 - tg/ran; 2 - rid; 3 - slot; 4 - cc; 5 - time(NULL) ; - printw ("--Call History----------------------------------------------------------------\n"); for (short int j = 0; j < 10; j++) { + //only print if a valid time was assinged to the matrix if ( ((time(NULL) - call_matrix[9-j][5]) < 9999) ) - //if (1 == 1) { - printw ("| #%d %s ", j, SyncTypes[call_matrix[9-j][0]]); - if (lls == 8 || lls == 9 || lls == 16 || lls == 17) - { - printw ("RAN [%2d] ", call_matrix[9-j][1]); - printw ("TG [%4d] ", call_matrix[9-j][4]); - printw ("RID [%4d] ", call_matrix[9-j][2]); - } - if (lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 || lls == 11 ) //P25 P1 and DMR - { - printw ("TID [%8d] ", call_matrix[9-j][1]); - printw ("RID [%8d] ", call_matrix[9-j][2]); - } - if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) //dPMR - { - printw ("TID [%8d] ", call_matrix[9-j][1]); - printw ("RID [%8d] ", call_matrix[9-j][2]); - printw ("DCC [%2d] ", call_matrix[9-j][4]); + printw ("| %s ", SyncTypes[call_matrix[9-j][0]]); + if (lls == 8 || lls == 9 || lls == 16 || lls == 17) + { + printw ("RAN [%2lld] ", call_matrix[9-j][1]); + printw ("TG [%4lld] ", call_matrix[9-j][4]); + printw ("RID [%4lld] ", call_matrix[9-j][2]); + } + //dPMR + if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) + { + printw ("TGT [%8lld] ", call_matrix[9-j][1]); + printw ("SRC [%8lld] ", call_matrix[9-j][2]); + printw ("DCC [%2lld] ", call_matrix[9-j][4]); + } + //P25P1 Voice and Data + if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1) + { + printw ("TID [%8lld] ", call_matrix[9-j][1]); + printw ("RID [%8lld] ", call_matrix[9-j][2]); + printw ("NAC [0x%03llX] ", call_matrix[9-j][4]); + } + //DMR BS Types + if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 ) + { + printw ("S[%d] ", call_matrix[9-j][3]); + printw ("TGT [%8lld] ", call_matrix[9-j][1]); + printw ("SRC [%8lld] ", call_matrix[9-j][2]); + printw ("DCC [%02lld] ", call_matrix[9-j][4]); + } + //DMR MS Types + if (call_matrix[9-j][0] == 32 || call_matrix[9-j][0] == 33 || call_matrix[9-j][0] == 34 ) + { + //printw ("S[%d] ", call_matrix[9-j][3]); + printw ("TGT [%8lld] ", call_matrix[9-j][1]); + printw ("SRC [%8lld] ", call_matrix[9-j][2]); + printw ("DCC [%02lld] ", call_matrix[9-j][4]); + } + printw ("%lld secs ago\n", time(NULL) - call_matrix[9-j][5]); } + } //end Call History + //fence bottom + printw ("------------------------------------------------------------------------------\n"); + attroff(COLOR_PAIR(4)); //cyan for history - //printw ("RID [%08d] ", call_matrix[9-j][2]); - //printw ("S %d - ", call_matrix[j][3]); - if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1) //P25P1 Voice - { - printw ("NAC [0x%3X] ", call_matrix[9-j][4]); - } - if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 ) //DMR Voice Types - { - printw ("DCC [%2d] ", call_matrix[9-j][4]); - } - printw ("%d secs ago\n", time(NULL) - call_matrix[9-j][5]); - } - //printw("\n"); - } - printw ("------------------------------------------------------------------------------\n"); - attroff(COLOR_PAIR(4)); //cyan for history - //put sync type at very bottom - //printw ("%s %s\n", state->ftype, state->fsubtype); //some ftype strings have extra spaces in them - //if (state->lastsynctype != -1) //is there a synctype 0? - //while((c = getch()) != '~') { - // printw ("%c\n",c);} - //c = getch(); - /* - if (c = getch() != '~') - { - printf ("%c\n",c); - printf ("closing NCurses"); - ncursesClose(); - } - */ - //debug sr printw - if (1==2) //disable this later on - { - - printw ("sr_0 = %16llX \n", state->sr_0); - printw ("sr_1 = %16llX \n", state->sr_1); - printw ("sr_2 = %16llX \n", state->sr_2); - printw ("sr_3 = %16llX \n", state->sr_3); - printw ("sr_4 = %16llX \n", state->sr_4); - printw ("sr_5 = %16llX \n", state->sr_5); - printw ("sr_6 = %16llX \n", state->sr_6); - - } - refresh(); -} + refresh(); +} //end ncursesPrinter void ncursesClose () { diff --git a/src/dsd_reset.c b/src/dsd_reset.c index e8aa893..ab6165d 100644 --- a/src/dsd_reset.c +++ b/src/dsd_reset.c @@ -96,12 +96,7 @@ resetState (dsd_state * state) state->nxdn_last_ran = 0; -//#ifdef TRACE_DSD -// state->debug_sample_index = 0; -// state->debug_label_file = NULL; -// state->debug_label_dibit_file = NULL; -// state->debug_label_imbe_file = NULL; -//#endif - + //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 } diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 96dccb1..2af17e0 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -94,6 +94,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } else if (opts->audio_in_type == 1) { result = sf_read_short(opts->audio_in_file, &sample, 1); + //fprintf (stderr, ".."); 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? @@ -300,8 +301,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) state->lastsample = sample; - //steal sample here for rtl input or stdin input - state->input_sample_buffer = sample; //sample or sum, honestly this seemt to be best place to grab this sadly, sounds terrible most everywhere else + } symbol = (sum / count); diff --git a/src/dsd_upsample.c b/src/dsd_upsample.c index 42623f4..a700acd 100644 --- a/src/dsd_upsample.c +++ b/src/dsd_upsample.c @@ -23,8 +23,19 @@ upsample (dsd_state * state, float invalue) int i, j, sum; float *outbuf1, c, d; - - outbuf1 = state->audio_out_float_buf_p; + if (state->currentslot == 0 && state->dmr_stereo == 1) + { + outbuf1 = state->audio_out_float_buf_p; + } + if (state->currentslot == 1 && state->dmr_stereo == 1) + { + outbuf1 = state->audio_out_float_buf_pR; + } + if (state->dmr_stereo == 0) + { + outbuf1 = state->audio_out_float_buf_p; + } + //outbuf1 = state->audio_out_float_buf_p; outbuf1--; c = *outbuf1; d = invalue; @@ -43,6 +54,33 @@ upsample (dsd_state * state, float invalue) *outbuf1 = d; outbuf1++; + if (state->currentslot == 1 && state->dmr_stereo == 1) + { + if (state->audio_out_idx2R > 24) + { + // smoothing + outbuf1 -= 16; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 6; i++) + { + sum = 0; + outbuf1 -= 2; + sum += (int)*outbuf1; + outbuf1 += 2; + sum += (int)*outbuf1; + outbuf1 += 2; + sum += (int)*outbuf1; + outbuf1 -= 2; + *outbuf1 = (sum / (float) 3); + outbuf1++; + } + outbuf1 -= 8; + } + } + } + if (state->currentslot == 0 && state->dmr_stereo == 1) + { if (state->audio_out_idx2 > 24) { // smoothing @@ -65,4 +103,30 @@ upsample (dsd_state * state, float invalue) outbuf1 -= 8; } } + } + if (state->dmr_stereo == 0) + { + if (state->audio_out_idx2 > 24) + { + // smoothing + outbuf1 -= 16; + for (j = 0; j < 4; j++) + { + for (i = 0; i < 6; i++) + { + sum = 0; + outbuf1 -= 2; + sum += (int)*outbuf1; + outbuf1 += 2; + sum += (int)*outbuf1; + outbuf1 += 2; + sum += (int)*outbuf1; + outbuf1 -= 2; + *outbuf1 = (sum / (float) 3); + outbuf1++; + } + outbuf1 -= 8; + } + } + } } diff --git a/src/dstar.c b/src/dstar.c index 9ca83e3..12a47d0 100644 --- a/src/dstar.c +++ b/src/dstar.c @@ -39,6 +39,9 @@ void processDSTAR(dsd_opts * opts, dsd_state * state) { unsigned int bitbuffer = 0; const int *w, *x; + //set carrier to 1 so ncurses will light up green + state->carrier = 1; + if (opts->errorbars == 1) { fprintf (stderr, "e:"); } @@ -56,7 +59,7 @@ void processDSTAR(dsd_opts * opts, dsd_state * state) { } else { framecount = 1; //just saw a sync frame; there should be 20 not 21 till the next } - + //why is this running in a loop for? while (sync_missed < 3) { memset(ambe_fr, 0, 96); @@ -86,6 +89,7 @@ void processDSTAR(dsd_opts * opts, dsd_state * state) { ambe_fr[*w][*x] = (1 & dibit); w++; x++; + } @@ -128,14 +132,31 @@ void processDSTAR(dsd_opts * opts, dsd_state * state) { slowdata[0] ^= 0x70; slowdata[1] ^= 0x4f; slowdata[2] ^= 0x93; - //fprintf (stderr, "unscrambled- %s",slowdata); + //fprintf (stderr, "unscrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] ); } else if (framecount == 0) { - //fprintf (stderr, "never scrambled-%s\n",slowdata); - } + //fprintf (stderr, "never scrambled-%c\n",slowdata); + //fprintf (stderr, "never scrambled- %02X %02X %02X %02X \n", slowdata[0], slowdata[1], slowdata[2], slowdata[3] ); + } + for (short int i = 0; i < 4; i++) + { + if (slowdata[i] <= 0x7E && slowdata[i] >=0x20) + { + //fprintf (stderr, "%c", slowdata[i]); + } + //else fprintf (stderr, "."); + } + //fprintf (stderr, "\n"); framecount++; - } + + //since we are in a while loop, run ncursesPrinter here. + if (opts->use_ncurses_terminal == 1) + { + ncursesPrinter(opts, state); + } + + } //end while loop end: if (opts->errorbars == 1) { fprintf (stderr, "\n"); @@ -153,7 +174,7 @@ void processDSTAR_HD(dsd_opts * opts, dsd_state * state) { // Note: These routines contain GPLed code. Remove if you object to that. // Due to this, they are in a separate source file. - dstar_header_decode(radioheaderbuffer); + dstar_header_decode(state, radioheaderbuffer); //We officially have sync now, so just pass on to the above routine: diff --git a/src/dstar_header.c b/src/dstar_header.c index 204ee7b..db7907c 100644 --- a/src/dstar_header.c +++ b/src/dstar_header.c @@ -19,8 +19,9 @@ #include "fcs.h" #include "descramble.h" #include "dstar_header.h" +#include "dsd.h" -void dstar_header_decode(int radioheaderbuffer[660]) { +void dstar_header_decode(dsd_state * state, int radioheaderbuffer[660]) { int radioheaderbuffer2[660]; unsigned char radioheader[41]; int octetcount, bitcount, loop; @@ -33,6 +34,7 @@ void dstar_header_decode(int radioheaderbuffer[660]) { deinterleave(radioheaderbuffer2, radioheaderbuffer); len = FECdecoder(radioheaderbuffer, radioheaderbuffer2); memset(radioheader, 0, 41); + //memset(state->dstarradioheader, 0, 41); // note we receive 330 bits, but we only use 328 of them (41 octets) // bits 329 and 330 are unused octetcount = 0; @@ -48,6 +50,14 @@ void dstar_header_decode(int radioheaderbuffer[660]) { bitcount = 0; } } + //state->dstarradioheader = radioheader; + + for (short i = 0; i < 41; i++) + { + state->dstarradioheader[i] = radioheader[i]; + } + + // print header fprintf (stderr, "\nDSTAR HEADER: "); //fprintf (stderr, "FLAG1: %02X - FLAG2: %02X - FLAG3: %02X\n", radioheader[0], diff --git a/src/nxdn_data.c b/src/nxdn_data.c index 82b0684..3dc93e2 100644 --- a/src/nxdn_data.c +++ b/src/nxdn_data.c @@ -66,12 +66,19 @@ void processNXDNData (dsd_opts * opts, dsd_state * state) //fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); if(CrcIsGood) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - fprintf (stderr, "(CRC OK) "); + fprintf (stderr, "%s", KNRM); + //fprintf (stderr, "(CRC OK) "); state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead } - else fprintf (stderr, "(CRC ERR) "); + else + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, "(CRC ERR) "); + fprintf (stderr, "%s", KNRM); + } /* Decode the SACCH only when all 4 voice frame diff --git a/src/nxdn_lib.c b/src/nxdn_lib.c index 786e781..22c8c75 100644 --- a/src/nxdn_lib.c +++ b/src/nxdn_lib.c @@ -732,6 +732,7 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) } /* Print the "Call Type" */ + fprintf (stderr, "%s", KGRN); fprintf(stderr, "\n %s - ", NXDN_Call_Type_To_Str(CallType)); //line break and 1 space //sprintf (state->nxdn_call_type, NXDN_Call_Type_To_Str(CallType)); //fix warning below //warning: format not a string literal and no format arguments [-Wformat-security] @@ -753,12 +754,16 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) /* Print the Key ID */ if(CipherType != 0) { + fprintf (stderr, "%s", KYEL); fprintf(stderr, "Key ID %u - ", KeyID & 0xFF); + fprintf (stderr, "%s", KNRM); //state->nxdn_key = (KeyID & 0xFF); } /* Print Source ID and Destination ID (Talk Group or Unit ID) */ + fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF); + fprintf (stderr, "%s", KNRM); if(state->NxdnElementsContent.VCallCrcIsGood) @@ -770,18 +775,15 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) state->nxdn_key = (KeyID & 0xFF); state->nxdn_cipher_type = CipherType; } - fprintf(stderr, "(CRC OK) "); + //fprintf(stderr, "(CRC OK) "); } //fprintf(stderr, " (OK) - "); - else fprintf(stderr, "(CRC ERR) "); - - //fprintf(stderr, "\nVCALL = "); - - //for(i = 0; i < 8; i++) - //{ - // fprintf(stderr, "0x%02X, ", ConvertBitIntoBytes(&Message[i * 8], 8) & 0xFF); - //} - //fprintf(stderr, "\n"); + else + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "(CRC ERR) "); + fprintf (stderr, "%s", KNRM); + } } /* End NXDN_decode_VCALL() */ diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index 3d3a270..04b12ab 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -80,11 +80,18 @@ void processNXDNVoice (dsd_opts * opts, dsd_state * state) //if(CrcIsGood) fprintf(stderr, " (OK) - "); if(CrcIsGood) { + fprintf (stderr, "%s", KCYN); fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - fprintf (stderr, "(CRC OK) "); + fprintf (stderr, "%s", KNRM); + //fprintf (stderr, "(CRC OK) "); state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead } - else fprintf(stderr, "(CRC ERR) "); + else + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "(CRC ERR) "); + fprintf (stderr, "%s", KNRM); + } /* Determine the current part of superframe diff --git a/src/p25p1_hdu.c b/src/p25p1_hdu.c index 5aa1d2f..1bdd2c7 100644 --- a/src/p25p1_hdu.c +++ b/src/p25p1_hdu.c @@ -469,19 +469,17 @@ processHDU(dsd_opts* opts, dsd_state* state) mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8); } - //if (state->errs == 0 && algidhex != 0x80) - if (1 == 1) //always print hdu alg info - //if (opts->payload == 1 && state->errs == 0) + if (1 == 1) //print on payload == 1 { - //fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi); - fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX MFID: 0x%02X \n", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX MFID: 0x%02X \n", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid); + fprintf (stderr, "%s", KNRM); } if (opts->p25enc == 1 && opts->payload == 0) { algidhex = strtol (algid, NULL, 2); kidhex = strtol (kid, NULL, 2); - //fprintf (stderr, "mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex); } if (opts->p25lc == 1) { diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c index fc0519a..2c6fe5f 100644 --- a/src/p25p1_ldu1.c +++ b/src/p25p1_ldu1.c @@ -51,7 +51,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) if (opts->errorbars == 1) { - fprintf (stderr, "e:"); + //fprintf (stderr, "e:"); } // IMBE 1 diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 0432f6a..c518c92 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -51,7 +51,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) if (opts->errorbars == 1) { - fprintf (stderr, "e:"); + //fprintf (stderr, "e:"); } // IMBE 1 @@ -375,18 +375,16 @@ processLDU2 (dsd_opts * opts, dsd_state * state) mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8); } - //if (state->errs == 0 && algidhex != 0x80) - if (1 == 1) //always print the LDU2 alg info - //if (opts->payload == 1 && state->errs == 0) + if (1 == 1) //print on payload == 1 { - //fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi); - fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3); + fprintf (stderr, "%s", KYEL); + fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3); + fprintf (stderr, "%s", KNRM); } - //if (opts->p25enc == 1 && opts->payload == 0) + if (opts->payload == 0) { algidhex = strtol (algid, NULL, 2); kidhex = strtol (kid, NULL, 2); - //fprintf (stderr, "mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex); } } diff --git a/src/p25p1_tdu.c b/src/p25p1_tdu.c index 4f4e501..432983a 100644 --- a/src/p25p1_tdu.c +++ b/src/p25p1_tdu.c @@ -22,7 +22,9 @@ processTDU (dsd_opts* opts, dsd_state* state) // Next we should find an status dibit if (status_count != 35) { + fprintf (stderr, "%s", KRED); fprintf (stderr, "*** SYNC ERROR\n"); + fprintf (stderr, "%s", KNRM); } // trailing status symbol diff --git a/src/p25p1_tdulc.c b/src/p25p1_tdulc.c index 1f5152a..2e56bf2 100644 --- a/src/p25p1_tdulc.c +++ b/src/p25p1_tdulc.c @@ -114,7 +114,9 @@ read_and_correct_dodeca_word (dsd_opts* opts, dsd_state* state, char* dodeca, in } else { + fprintf (stderr, "%s", KRED); fprintf (stderr, " IRRECOVERABLE"); + fprintf (stderr, "%s", KNRM); } fprintf (stderr, "\n"); #endif @@ -293,7 +295,9 @@ processTDULC (dsd_opts* opts, dsd_state* state) // Next we should find an status dibit if (status_count != 35) { + fprintf (stderr, "%s", KRED); fprintf (stderr, "*** SYNC ERROR\n"); + fprintf (stderr, "%s", KNRM); } // trailing status symbol diff --git a/src/trellis.cpp b/src/trellis.cpp index e667bbd..73b4315 100644 --- a/src/trellis.cpp +++ b/src/trellis.cpp @@ -1,8 +1,7 @@ /* * Copyright (C) 2016 by Jonathan Naylor, G4KLX * - * Modifications of original code to work with OP25 - * Copyright (C) 2019 by Graham J. Norbury + * 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 @@ -14,7 +13,6 @@ * GNU General Public License for more details. */ #include "dsd.h" -//#include "trellis.h" #include #include @@ -52,6 +50,23 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U #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) { @@ -101,44 +116,107 @@ void CDMRTrellisTribitsToBits(const unsigned char* tribits, unsigned char* paylo // 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]; + //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; i++) { + 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] == ENCODE_TABLE[state * 8U + j]) { - if (points[i] == DECODE_TABLE[state * 8U + j]) { - //if (points[48-i] == DECODE_TABLE[state * 8U + j]) { + 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) - return i; + { + 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 + } - state = tribits[i]; + //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; + } } - - //if (tribits[48U] != 0U) - if (tribits[48U] != 0U) // - { - return 48U; - } - - return 999U; } @@ -146,7 +224,8 @@ 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; @@ -157,19 +236,44 @@ void CDMRTrellisDeinterleave(const unsigned char* data, signed char* dibits) bool b2 = data[n] != 0x0; if (!b1 && b2) - dibit = +3; + dibit = +3; // 1 - 01 else if (!b1 && !b2) - dibit = +1; + dibit = +1; // 0 - 00 else if (b1 && !b2) - dibit = -1; + dibit = -1; // 2 - 10 else - dibit = -3; + dibit = -3; // 3 - 11 - n = INTERLEAVE_TABLE[i]; //should this go in reverse? - dibits[n] = dibit; + */ + //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) @@ -324,7 +428,7 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) } signed char dibits[98U]; CDMRTrellisDeinterleave(data, dibits); - if (1 == 1) + if (1 == 2) { fprintf (stderr, "\n Trellis Deinterleaved Dibits inside Decoder (converted to signed)\n "); for (short i = 0; i < 98; i++) @@ -333,8 +437,19 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) } } unsigned char points[49U]; + unsigned char reverse_points[49U]; CDMRTrellisDibitsToPoints(dibits, points); - if (1 == 1) + //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++) @@ -343,19 +458,11 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) } } // Check the original code - unsigned char reverse_points[49U]; - fprintf (stderr, "\n Trellis Reversed 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]); - } - //unsigned int failPos = CDMRTrellisCheckCode(points, tribits); - unsigned int failPos = CDMRTrellisCheckCode(reverse_points, tribits); + unsigned int failPos = CDMRTrellisCheckCode(points, tribits); + //unsigned int failPos = CDMRTrellisCheckCode(reverse_points, tribits); //stack smashing detected terminated - - if (1 == 1) + if (1 == 2) { fprintf (stderr, "\n Check Code Trellis Tribits inside Decoder\n "); for (short i = 0; i < 49; i++) @@ -367,27 +474,36 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) if (failPos == 999U) { CDMRTrellisTribitsToBits(tribits, payload); - if (1 == 1) + if (1 == 2) { - fprintf (stderr, "\nTrellis Payload Tribits to Bits failPos == 999U\n "); - for (short i = 0; i < 18; i++) + 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]; + savePoints[i] = points[i]; + //savePoints[i] = reverse_points[i]; - //bool ret = CDMRTrellisFixCode(points, failPos, payload); - bool ret = CDMRTrellisFixCode(reverse_points, failPos, payload); + bool ret = CDMRTrellisFixCode(points, failPos, payload); + //bool ret = CDMRTrellisFixCode(reverse_points, failPos, payload); if (ret){ - if (1 == 1) + if (1 == 2) { fprintf (stderr, "\n if return Trellis Tribits inside Decoder\n "); for (short i = 0; i < 49; i++) @@ -396,7 +512,7 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) } } - if (1 == 1) + 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++) @@ -408,9 +524,9 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) if (failPos == 0U) { - if (1 == 1) + if (1 == 2) { - fprintf (stderr, "\nTrellis Payload Tribits to Bits failPos == 0U\n "); + fprintf (stderr, "\nTrellis Payload Tribits to Bytes failPos == 0U\n "); for (short i = 0; i < 18; i++) { fprintf (stderr, "[%02X]", payload[i]); diff --git a/src/ysf.c b/src/ysf.c new file mode 100644 index 0000000..8882036 --- /dev/null +++ b/src/ysf.c @@ -0,0 +1,287 @@ +/*------------------------------------------------------------------------------- + * ysf.c + * Yaesu Fusion Decoder for DSD + * + * LWVMOBILE + * 2022-04 DSD-FME Florida Man Edition + *-----------------------------------------------------------------------------*/ + /* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + +#include "dsd.h" + +const int fichInterleave[100] = { + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, + 1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 76, 81, 86, 91, 96, + 2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, + 3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78, 83, 88, 93, 98, + 4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, 84, 89, 94, 99, +}; + +const int vd2Interleave[104] = { + 0, 26, 52, 78, + 1, 27, 53, 79, + 2, 28, 54, 80, + 3, 29, 55, 81, + 4, 30, 56, 82, + 5, 31, 57, 83, + 6, 32, 58, 84, + 7, 33, 59, 85, + 8, 34, 60, 86, + 9, 35, 61, 87, + 10, 36, 62, 88, + 11, 37, 63, 89, + 12, 38, 64, 90, + 13, 39, 65, 91, + 14, 40, 66, 92, + 15, 41, 67, 93, + 16, 42, 68, 94, + 17, 43, 69, 95, + 18, 44, 70, 96, + 19, 45, 71, 97, + 20, 46, 72, 98, + 21, 47, 73, 99, + 22, 48, 74, 100, + 23, 49, 75, 101, + 24, 50, 76, 102, + 25, 51, 77, 103 +}; + +const int vfrInterleave[144] = { //IMBE 7200x4400 full rate interleave schedule + 0, 24, 48, 72, 96, 120, 25, 1, 73, 49, 121, 97, + 2, 26, 50, 74, 98, 122, 27, 3, 75, 51, 123, 99, + 4, 28, 52, 76, 100, 124, 29, 5, 77, 53, 125, 101, + 6, 30, 54, 78, 102, 126, 31, 7, 79, 55, 127, 103, + 8, 32, 56, 80, 104, 128, 33, 9, 81, 57, 129, 105, + 10, 34, 58, 82, 106, 130, 35, 11, 83, 59, 131, 107, + 12, 36, 60, 84, 108, 132, 37, 13, 85, 61, 133, 109, + 14, 38, 62, 86, 110, 134, 39, 15, 87, 63, 135, 111, + 16, 40, 64, 88, 112, 136, 41, 17, 89, 65, 137, 113, + 18, 42, 66, 90, 114, 138, 43, 19, 91, 67, 139, 115, + 20, 44, 68, 92, 116, 140, 45, 21, 93, 69, 141, 117, + 22, 46, 70, 94, 118, 142, 47, 23, 95, 71, 143, 119 +}; + +//half-rate ambe3600x2450 interleave schedule +const int YSFrW[36] = { + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +// bit index +const int YSFrX[36] = { + 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +// bit 0 +// frame index +const int YSFrY[36] = { + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +// bit index +const int YSFrZ[36] = { + 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +void processYSF(dsd_opts * opts, dsd_state * state) //YSF +{ + //480 dibits - 20 dibit sync leaves 460 dibits (920 bits) each 'superframe' + fprintf (stderr, "processYSF Function \n"); + uint32_t i, j, k; + unsigned char dibit; + const int *w, *x, *y, *z; + char ambe_fr[8][4][24]; + unsigned char storage[8][4][24]; //may expand later + unsigned char discard[460]; //just set up for now to hold random dibit grabs with nothing to do but skip them + unsigned char vch[4][36]; //correct size array for 4*32 dibit VD2 VCH? + unsigned char fich[200]; //store as bits after deinterleaving + unsigned char fichraw[100]; + unsigned char fichdibits[100]; //deinterleaved fich dibits + unsigned char fichbytes[26]; + unsigned int fi = 0; + unsigned int cs = 0; + unsigned int cm = 0; + unsigned int bn = 0; + unsigned int bt = 0; + unsigned int fn = 0; + unsigned int ft = 0; + unsigned int mr = 0; + unsigned int ip = 0; + unsigned int dt = 0; //DT, 2 bytes (according to manual, but has to be two bits) + unsigned int sq = 0; + unsigned int sc = 0; + int vd1 = 1; + int vd2 = 0; + unsigned int msbI = 0; + unsigned int lsbI = 0; + unsigned char vd2BitsRaw[104]; + opts->inverted_ysf = 0; //here for testing purposes, move to main later + for (i = 0; i < 100; i++) //100 dibits for fich + { + dibit = getDibit (opts, state); + + if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 + { + dibit = (dibit ^ 2); + } + fichraw[i] = dibit; //raw storage for debug + fichdibits[fichInterleave[i]] = dibit; //sort into proper order + //fich[i*2] = (1 & (dibit >> 1)); // bit 1 + //fich[i*2+1] = (1 & dibit); // bit 0 + fich[i*2] = (fichdibits[fichInterleave[i]] >> 1) & 1; + //fprintf (stderr, "%b", fich[i*2]); + fich[i*2+1] = fichdibits[fichInterleave[i]] & 1; + //fprintf (stderr, "%b", fich[i*2+1]); + if (i == 4) + { + //datatype = dibit; + } + } + //fprintf (stderr, "\nFICH BYTES = "); + for (i = 0; i < 25; i++) //bits to bytes + { + fichbytes[i] = 0; //initialize to see what isn't beign set + fichbytes[i] = ( (fich[i*8] << 7) | (fich[i*8+1] << 6) | (fich[i*8+2] << 5) | (fich[i*8+3] << 4) | + (fich[i*8+4] << 3) | (fich[i*8+5] << 2) | (fich[i*8+6] << 1) | (fich[i*8+7] << 0) ); + //fprintf (stderr, "[%02X]", fichbytes[i]); + } + //fprintf (stderr, "\n"); + //datatype = (fich[8] << 1) + fich[9]; + dt = fichbytes[2] & 0x03; + for (i = 0; i < 2; i++) + { + //datatype << 1; + //datatype = datatype | fichraw[i+8]; + //fprintf (stderr, "%02b", fichdibits[i+4]); + //fprintf (stderr, "%02b", fichdibits[i+11]); + } + //fprintf (stderr, "Datatype = %02b\n", dt); + //quick dirty VD1 method? + if (0 == 0) //dt == 0 for VD1 + { + fprintf (stderr, "processYSF VD1 \n"); + for (j = 0; j < 5; j++) //5 DCH and VCH + { + w = YSFrW; + x = YSFrX; + y = YSFrY; + z = YSFrZ; + k = 0; + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); + + if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 + { + dibit = (dibit ^ 2); + } + + storage[j][*w][*x] = (1 & (dibit >> 1)); // bit 1 + storage[j][*y][*z] = (1 & dibit); // bit 0 + + } + + + + //AMBE VCH + for (i = 0; i < 36; i++) + { + dibit = getDibit (opts, state); + + if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 + { + dibit = (dibit ^ 2); + } + + ambe_fr[j][*w][*x] = (1 & (dibit >> 1)); // bit 1 + ambe_fr[j][*y][*z] = (1 & dibit); // bit 0 + w++; + x++; + y++; + z++; + } + //processMbeFrame (opts, state, NULL, ambe_fr[j], NULL); + } //end j < 4 loop + } //end VD1 + //move processMbeFrame to outside of dibit loop to prevent slip + for (j = 0; j < 5; j++) + { + //processMbeFrame (opts, state, NULL, ambe_fr[j], NULL); + } + //VD2 method + if (0 == 3) //dt == 3 + { + fprintf (stderr, "processYSF VD2 \n"); + for (j = 0; j < 4; j++) + { + //VCH[j] and VeCH[j] + for (i = 0; i < 20; i++) //32? + { + dibit = getDibit (opts, state); + + if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 + { + dibit = (dibit ^ 2); + } + //collect dibits into array for processing + vch[j][i] = dibit; + w = YSFrW; + x = YSFrX; + y = YSFrY; + z = YSFrZ; + msbI = vd2Interleave[(j+1)*i]; //don't this this is remotely correct, really could use the manual right about now + lsbI = vd2Interleave[(j+1)*i+1]; + vd2BitsRaw[msbI] = ((vch[j][i] >> 1) & 1); + vd2BitsRaw[lsbI] = (vch[j][i] & 1); + } // VCH[j] + //DCH[j] + for (i = 0; i < 20; i++) //32? + { + dibit = getDibit (opts, state); + + if (opts->inverted_ysf == 1) //opts->inverted_ysf == 1 + { + dibit = (dibit ^ 2); + } + discard[i] = dibit; + } //end DCH[j] + } //end for j loop + + } //end VD2 + +} //end processYSF