diff --git a/CMakeLists.txt b/CMakeLists.txt index fb6f787..5ef5dff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ find_package(MBE REQUIRED) find_package(ITPP REQUIRED) find_package(RTLSDR) find_package(Curses REQUIRED) -find_package(PULSEAUDIO) +find_package(PULSEAUDIO REQUIRED) include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}) set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY}) diff --git a/README.md b/README.md index 0a55595..d58048f 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,34 @@ -# Digital Speech Decoder - Florida Man Edition - -![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme.png) +# 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"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), and [LFSR](https://github.com/mattames/LFSR "LFSR"). This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu and hrh17 for the many hours of wav samples submitted by them. -## 2022.06.20 Update - Current Users Please Read!! ## -The executable for this project has been changed from `dsd` to `dsd-fme` so after pulling or cloning the lastest version, make sure to call the software with `dsd-fme`. It may also be beneficial to open your current build folder and run `sudo make uninstall` to uninstall the binary named `dsd` or to run `sudo rm /usr/local/bin/dsd` to alleviate any confusion or from accidentally calling the older version as it will still be installed along with the new `dsd-fme` executable. The Summer Cleanup Project has also seen a lot of the files that weren't in use, or used for github workflows and cmake files removed from the project folder, slimming it down quite considerably. If you have any issue doing a git pull to get the current version, you may need to instead do a fresh clone, build, and install in a clean folder. Check the info below about running download-and-install-nodeps.sh if needed. +## 2022.08.12 Update ## +A new menu system has been introduced in the NCURSES Terminal. While running DSD-FME, a user can simply use the ESC or arrow keys to open the menu and change options on the fly. This is extremely beneficial when wanting to change settings on the fly, and also to alleviate the need to use complex start up command line arguments. All of the previous command line arguments still work and will get you up faster, but if you would rather configure after start up, or change settings while running, the menu system is very helpful in that regard. -## 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, MBE file saving and WAV file saving 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. +[![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme.png)](https://www.youtube.com/watch?v=TqTfAfaPJ4s "DSD-FME Update 2022.08.12") -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. +To get started with the new menu system, simply launch with: + +`dsd-fme -N 2> log.txt` + +Virtually all the examples listed below can now be set up on the fly with the menu system, no need to check the help or refer to this page. + +This release also has provisional support for playing back OP25 capture bin files, and the creation and playback of its own capture bin files as well (most likely not OP25 compatible). Mileage may vary. Be sure to choose the decoder option required when playing a bin file back, do not rely on auto-detect. Capture Bin files can be used to reliably replay P25, DMR BS, and NXDN decodings, and can replace the need for MBE file saving in the case of DMR Stereo, allowing for a complete replay of all events on a system, rather than just voice only. + +Per Call wav file creation has been implemented, currently only for DMR Stereo. Complete audio decode wav is available for all other decoder types. LRRP has been revamped, working more consistently, and an option to dump LRRP data to ~/lrrp.txt in the user home directory now exists, and can be imported into open-source QGIS to provide mapping data for LRRP output. Simply open the newly included map file in QGIS and point it at your geographic region. (Be sure the lrrp.txt file exists, and has data populated in it prior to opening the map file in QGIS, otherwise, the map layer may not want to show back up!) + +DMR Data Header decoding has been revamped, and most data burst decoding types tightened up and code cleaned. FEC error checking now implemented on CACH and Burst types, cleaning up some erroneous slot and burst errors. + +## 2022.06.20 Update - Current Users Please Read!! ## +The executable for this project has been changed from `dsd` to `dsd-fme` so after pulling or cloning the lastest version, make sure to call the software with `dsd-fme`. + +## 2022.05.05 Update ## +DMR Stereo method added for listening to voice audio in both TDMA channels/slots simultaneously. ### Example Usage and Note! `dsd-fme` or `./dsd-fme` may need to be used in your usage, depending on if you are running it from the build folder, or if you have run make install. You will need to tweak the examples to your particular usage. Users can always check `dsd-fme -h` for help and all command line switches to use. -`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR, P25P1, D-STAR, and X2-TDMA decoding. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed. +`dsd-fme` 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. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed. ``` -fi NXDN48 @@ -39,8 +47,6 @@ and in a second terminal tab, same folder, run `tail -n 40 -f voice.log` -![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme2.png) - Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently) ## Example Usage - RTL2832 Dongle Input @@ -79,24 +85,27 @@ and in a second terminal tab, same folder, run `tail -n 40 -f voice.log` +![DSD-FME](https://github.com/lwvmobile/dsd-fme/blob/pulseaudio/dsd-fme2.png) + ## Roadmap The Current list of objectives include: -1. ~~Random Tinkering~~ More Random Tinkering +1. Include P25 P2 Audio decoding with capture bin files, then RTL input and/or disc tap input. +~~Random Tinkering~~ ~~More Random Tinkering~~ -2. ~~Implemented Pulse Audio~~ Remove remaining PortAudio code, ~~improved Pulse Audio for stereo output and channel/slot separation~~ and reimplement wav file saving using DMR Stereo method for stereo wav files, or seperate as per call wav files. +2. ~~Implemented Pulse Audio~~ ~~Remove remaining PortAudio code,~~ ~~improved Pulse Audio for stereo output and channel/slot separation~~ ~~and reimplement wav file saving using DMR Stereo method for stereo wav files, or seperate as per call wav files.~~ -3. ~~Improve NXDN and DMR support~~ Continue to improve ~~NXDN and DMR~~ all data and voice decoding. +3. ~~Improve NXDN and DMR support~~ Continue to improve ~~NXDN and DMR~~ all data and voice decoding. 4. ~~More Concise Printouts - Ncurses~~ -5. ~~Make simple to use installer script.~~ +5. ~~Make simple to use installer script.~~ ## How to clone, check out, and build this branch ### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer: -Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 22.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately. +Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 22.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately. If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run: @@ -119,7 +128,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 Debian/Ubuntu based distros. Check your package manager for equivalent packages if different. +First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different. ``` sudo apt update @@ -139,7 +148,7 @@ sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat l wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files tar xjf itpp* #if you can't cd into this folder, double check folder name first -cd itpp-4.3.1 +cd itpp-4.3.1 mkdir build cd build cmake .. @@ -199,7 +208,6 @@ Already have this branch, and just want to pull the latest build? You can run th git pull https://github.com/lwvmobile/dsd-fme pulseaudio ##cd into your build folder## cd build -##cmake usually isn't necesary, but could be if I update the cmakelist.txt cmake .. make -j `nproc` sudo make install @@ -225,5 +233,3 @@ GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - diff --git a/dsd-fme-qgis-map.qgz b/dsd-fme-qgis-map.qgz new file mode 100644 index 0000000..0552ba6 Binary files /dev/null and b/dsd-fme-qgis-map.qgz differ diff --git a/dsd-fme.png b/dsd-fme.png index d45c8d4..d76473a 100644 Binary files a/dsd-fme.png and b/dsd-fme.png differ diff --git a/dsd-fme2.png b/dsd-fme2.png index 6ea3e53..85a88b9 100644 Binary files a/dsd-fme2.png and b/dsd-fme2.png differ diff --git a/include/dsd.h b/include/dsd.h index 2f24a67..67ffb25 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -40,12 +40,7 @@ #include #include #include -#ifdef SOLARIS -#include -#endif -#if defined(BSD) && !defined(__APPLE__) -#include -#endif + #include #include #include @@ -54,29 +49,16 @@ #include //PULSE AUDIO #include //PULSE AUDIO -//#include //PUlSE AUDIO #define SAMPLE_RATE_IN 48000 //48000 #define SAMPLE_RATE_OUT 8000 //8000, -#ifdef USE_PORTAUDIO -#include "portaudio.h" -#define PA_FRAMES_PER_BUFFER 64 -//Buffer needs to be large enough to prevent input buffer overruns while DSD is doing other struff (like outputting voice) -//else you get skipped samples which result in incomplete/erronous decodes and a mountain of error messages. -#define PA_LATENCY_IN 0.500 -//Buffer needs to be large enough to prevent output buffer underruns while DSD is doing other stuff (like decoding input) -//else you get choppy audio and in 'extreme' cases errors. -//Buffer also needs to be as small as possible so we don't have a lot of audio delay. -#define PA_LATENCY_OUT 0.100 -#endif - #ifdef USE_RTLSDR #include #endif -//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 + +#include +#include static volatile int exitflag; @@ -153,18 +135,6 @@ typedef struct uint8_t NextIVComputed[8]; } NxdnElementsContent_t; - -enum -{ - MODE_UNENCRYPTED, - MODE_BASIC_PRIVACY, - MODE_ENHANCED_PRIVACY_ARC4, - MODE_ENHANCED_PRIVACY_AES256, - MODE_HYTERA_BASIC_40_BIT, - MODE_HYTERA_BASIC_128_BIT, - MODE_HYTERA_BASIC_256_BIT -}; - //Read Solomon (12,9) constant #define RS_12_9_DATASIZE 9 #define RS_12_9_CHECKSUMSIZE 3 @@ -281,20 +251,16 @@ typedef struct int audio_in_fd; SNDFILE *audio_in_file; SF_INFO *audio_in_file_info; -#ifdef USE_PORTAUDIO - PaStream* audio_in_pa_stream; -#endif + uint32_t rtlsdr_center_freq; int rtlsdr_ppm_error; //was int, changed to float - int audio_in_type; // 0 for device, 1 for file, 2 for portaudio, 3 for rtlsdr + int audio_in_type; // 0 for device, 1 for file, 3 for rtlsdr char audio_out_dev[1024]; int audio_out_fd; SNDFILE *audio_out_file; SF_INFO *audio_out_file_info; -#ifdef USE_PORTAUDIO - PaStream* audio_out_pa_stream; -#endif - int audio_out_type; // 0 for device, 1 for file, 2 for portaudio + + int audio_out_type; // 0 for device, 1 for file, int split; int playoffset; int playoffsetR; @@ -302,11 +268,19 @@ typedef struct char mbe_out_file[1024]; char mbe_out_path[1024]; FILE *mbe_out_f; + FILE *symbol_out_f; float audio_gain; float audio_gainR; int audio_out; + int dmr_stereo_wav; char wav_out_file[1024]; + char wav_out_fileR[1024]; + char wav_out_file_raw[1024]; + char symbol_out_file[1024]; + short int symbol_out; SNDFILE *wav_out_f; + SNDFILE *wav_out_fR; + SNDFILE *wav_out_raw; //int wav_out_fd; int serial_baud; char serial_dev[1024]; @@ -315,6 +289,7 @@ typedef struct int frame_dstar; int frame_x2tdma; int frame_p25p1; + int frame_p25p2; int frame_nxdn48; int frame_nxdn96; int frame_dmr; @@ -338,17 +313,16 @@ typedef struct int rtl_volume_multiplier; int rtl_udp_port; int rtl_bandwidth; + int rtl_started; int monitor_input_audio; int pulse_raw_rate_in; 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; @@ -356,23 +330,28 @@ typedef struct pa_simple *pulse_digi_dev_out; pa_simple *pulse_digi_dev_outR; int use_ncurses_terminal; + int ncurses_compact; + int ncurses_history; int reset_state; int payload; char output_name[1024]; - int EncryptionMode; - unsigned int dPMR_curr_frame_is_encrypted; int dPMR_next_part_of_superframe; int inverted_dpmr; int frame_dpmr; - // - short int dmr_stereo; - // + short int dmr_stereo; + short int lrrp_file_output; + + short int dmr_mute_encL; + short int dmr_mute_encR; + 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 + int inverted_ysf; + short int aggressive_framesync; + + FILE *symbolfile; } dsd_opts; @@ -380,8 +359,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 *dmr_payload_buf; + int *dmr_payload_p; int repeat; short *audio_out_buf; short *audio_out_buf_p; @@ -415,13 +394,15 @@ typedef struct int maxbuf[1024]; int minbuf[1024]; int midx; - char err_str[64]; //actual error errorbars - char err_buf[64]; //make copy of err_str for comparison, only have string print when strcmp is different?? + char err_str[64]; + char err_buf[64]; char err_strR[64]; char err_bufR[64]; char fsubtype[16]; char ftype[16]; int symbolcnt; + int symbolc; + int rf_mod; int numflips; int lastsynctype; @@ -473,12 +454,12 @@ typedef struct int payload_mfid; int payload_mfidR; int payload_mi; - int payload_miR; //check to see if anything tied to this still functions appropriately - uint64_t payload_miP; - int payload_lsfr; - int payload_lsfrR; + int payload_miR; + unsigned long long int payload_miN; + unsigned long long int payload_miP; + int p25vc; unsigned long long int K; - int M; + int menuopen; unsigned int debug_audio_errors; unsigned int debug_audio_errorsR; @@ -506,7 +487,8 @@ typedef struct unsigned int nxdn_key; char nxdn_call_type[1024]; char dmr_callsign[2][6][99]; //plenty of room in case of overflow; - char dmr_lrrp[2][6][9999]; + char dmr_lrrp[2][6][9999]; //memory hog + unsigned long long int dmr_lrrp_source[2]; NxdnSacchRawPart_t NxdnSacchRawPart[4]; NxdnFacch1RawPart_t NxdnFacch1RawPart[2]; @@ -539,16 +521,21 @@ typedef struct TimeSlotVoiceSuperFrame_t TS2SuperFrame; char dmr_branding[25]; - 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 - //uint8_t dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame + uint8_t dmr_12_rate_sf[2][288]; //was 84, expanded to 288 to prevent possible crash if more comes in than expected + uint8_t dmr_34_rate_sf[2][288]; //was 96, expanded to 288 to prevent possible crash if more comes in than expected + int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame + uint8_t data_header_blocks[2]; //collect number of blocks to follow from data header per slot + uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot + uint8_t data_header_format[2]; //collect format of data header (conf or unconf) per slot + uint8_t data_header_sap[2]; //collect sap info per slot + uint8_t data_block_counter[2]; //counter for number of data blocks collected + uint8_t data_p_head[2]; //flag for dmr proprietary header to follow dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame; //These flags are used to known the DMR frame - //printing format (hex or binary) + //printing format (hex or binary) int printDMRRawVoiceFrameHex; int printDMRRawVoiceFrameBin; int printDMRRawDataFrameHex; @@ -557,7 +544,7 @@ typedef struct int printDMRAmbeVoiceSampleBin; //These flags are used to known the dPMR frame - //orinting format (hex or binary) + //orinting format (hex or binary) int printdPMRRawVoiceFrameHex; int printdPMRRawVoiceFrameBin; int printdPMRRawDataFrameHex; @@ -574,10 +561,11 @@ typedef struct short int dmr_ms_mode; unsigned int dmrburstL; unsigned int dmrburstR; - int dropL; - int dropR; unsigned long long int R; - + // int block_count; + short int dmr_encL; + short int dmr_encR; + //dstar header for ncurses unsigned char dstarradioheader[41]; @@ -604,6 +592,21 @@ typedef struct #define INV_P25P1_SYNC "333331331133111131311111" #define P25P1_SYNC "111113113311333313133333" +//preliminary P2 sync + +// static const uint64_t P25P2_FRAME_SYNC_MAGIC = 0x575D57F7FFLL; // 40 bits +// static const uint64_t P25P2_FRAME_SYNC_REV_P = 0x575D57F7FFLL ^ 0xAAAAAAAAAALL; +#define P25P2_SYNC "11131131111333133333" +#define INV_P25P2_SYNC "33313313333111311111" +// static const uint64_t P25P2_FRAME_SYNC_MASK = 0xFFFFFFFFFFLL; //wonder what the mask was for if its all F +// +// static const uint64_t P25P2_FRAME_SYNC_N1200 = 0x0104015155LL; +//#define P25P2_SYNC_N "" +// static const uint64_t P25P2_FRAME_SYNC_X2400 = 0xa8a2a8d800LL; +//#define P25P2_SYNC_X "" +// static const uint64_t P25P2_FRAME_SYNC_P1200 = 0xfefbfeaeaaLL; +//#define P25P2_SYNC_P "" + #define X2TDMA_BS_VOICE_SYNC "113131333331313331113311" #define X2TDMA_BS_DATA_SYNC "331313111113131113331133" #define X2TDMA_MS_DATA_SYNC "313113333111111133333313" @@ -628,9 +631,8 @@ typedef struct #define DMR_MS_DATA_SYNC "311131133313133331131113" #define DMR_MS_VOICE_SYNC "133313311131311113313331" -//inversion testing on MS -//#define DMR_MS_DATA_SYNC "133313311131311113313331" -//#define DMR_MS_VOICE_SYNC "311131133313133331131113" +//Testing NXDN FSW again +#define NXDN_FSW "3131331131" #define DMR_RC_DATA_SYNC "131331111133133133311313" @@ -670,7 +672,10 @@ void processAudio (dsd_opts * opts, dsd_state * state); 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 closePulseInput (dsd_opts * opts); +void closePulseOutput (dsd_opts * opts); void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void writeSynthesizedVoiceR (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); @@ -690,7 +695,17 @@ void openMbeInFile (dsd_opts * opts, dsd_state * state); void closeMbeOutFile (dsd_opts * opts, dsd_state * state); void openMbeOutFile (dsd_opts * opts, dsd_state * state); void openWavOutFile (dsd_opts * opts, dsd_state * state); +void openWavOutFileL (dsd_opts * opts, dsd_state * state); +void openWavOutFileR (dsd_opts * opts, dsd_state * state); +void openWavOutFileRaw (dsd_opts * opts, dsd_state * state); +void openSymbolOutFile (dsd_opts * opts, dsd_state * state); +void closeSymbolOutFile (dsd_opts * opts, dsd_state * state); +void writeSymbolOutFile (dsd_opts * opts, dsd_state * state); +void writeRawSample (dsd_opts * opts, dsd_state * state, short sample); void closeWavOutFile (dsd_opts * opts, dsd_state * state); +void closeWavOutFileL (dsd_opts * opts, dsd_state * state); +void closeWavOutFileR (dsd_opts * opts, dsd_state * state); +void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state); void printFrameInfo (dsd_opts * opts, dsd_state * state); void processFrame (dsd_opts * opts, dsd_state * state); void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation); @@ -724,22 +739,20 @@ void processX2TDMAdata (dsd_opts * opts, dsd_state * state); void processX2TDMAvoice (dsd_opts * opts, dsd_state * state); void processDSTAR_HD (dsd_opts * opts, dsd_state * state); void processYSF(dsd_opts * opts, dsd_state * state); //YSF +void processP2(dsd_opts * opts, dsd_state * state); //P2 short dmr_filter(short sample); short nxdn_filter(short sample); - 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); uint32_t ConvertAsciiToByte(uint8_t AsciiMsbByte, uint8_t AsciiLsbByte, uint8_t * OutputByte); void Convert49BitSampleInto7Bytes(char * InputBit, char * OutputByte); void Convert7BytesInto49BitSample(char * InputByte, char * OutputBit); -// -//ifdef ncurses -void ncursesOpen (); + +void ncursesOpen (dsd_opts * opts, dsd_state * state); void ncursesPrinter (dsd_opts * opts, dsd_state * state); void ncursesClose (); -//endif ncurses /* NXDN frame decoding functions */ void ProcessNXDNFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted); @@ -763,7 +776,7 @@ uint8_t NXDN_decode_LICH(uint8_t InputLich[8], uint8_t * Option, uint8_t * Direction, uint8_t * CompleteLichBinaryFormat, - uint8_t Inverted); + uint8_t Inverted); uint8_t NXDN_SACCH_raw_part_decode(uint8_t * Input, uint8_t * Output); void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state); uint8_t NXDN_FACCH1_decode(uint8_t * Input, uint8_t * Output); @@ -778,12 +791,11 @@ char * NXDN_Cipher_Type_To_Str(uint8_t CipherType); uint16_t CRC15BitNXDN(uint8_t * BufferIn, uint32_t BitLength); 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); - void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state); void printdPMRAmbeVoiceSample(dsd_opts * opts, dsd_state * state); void printdPMRRawVoiceFrame (dsd_opts * opts, dsd_state * state); + //dPMR functions void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferOut, uint32_t NbOfBitToScramble); void DeInterleave6x12DPmrBit(uint8_t * BufferIn, uint8_t * BufferOut); @@ -825,11 +837,11 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]); 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 ProcessReservedData(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]); + //LFSR code courtesy of https://github.com/mattames/LFSR/ int LFSR(dsd_state * state); -int LFSRP(dsd_state * state); void Hamming_7_4_init(); void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits); @@ -876,7 +888,7 @@ extern "C" { #endif void open_rtlsdr_stream(dsd_opts *opts); void cleanup_rtlsdr_stream(); -void get_rtlsdr_sample(int16_t *sample); +void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state); void rtlsdr_sighandler(); //TRELLIS @@ -890,8 +902,6 @@ 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/nxdn_const.h b/include/nxdn_const.h index 8b34ccf..85a5896 100644 --- a/include/nxdn_const.h +++ b/include/nxdn_const.h @@ -76,7 +76,7 @@ extern const int DSDNXDN_UDCH_m_PunctureList[58]; */ const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 }; //const unsigned char nxdnpr2[384] = -const unsigned char nxdnpr2[182] = //is this a problem, should it be 384/2 for dibits? +const unsigned char nxdnpr2[182] = //generated from default in manual with the x^9+x^4+1 poly? { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, diff --git a/src/dmr_bs.c b/src/dmr_bs.c index 886ac7b..f68d95e 100644 --- a/src/dmr_bs.c +++ b/src/dmr_bs.c @@ -10,13 +10,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state) 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] = {0}; char syncdata[48] = {0}; - char cachdata[13] = {0}; + //char cachdata[13] = {0}; int mutecurrentslot; int msMode; char cc[4]; @@ -29,6 +27,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state) unsigned short int vc1; unsigned short int vc2; + //cach fec + char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug + int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + + //add time to mirror printFrameSync time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp @@ -67,17 +70,34 @@ void dmrBS (dsd_opts * opts, dsd_state * state) for(i = 0; i < 12; i++) { dibit = getDibit(opts, state); - cachdata[i] = dibit; state->dmr_stereo_payload[i] = dibit; - //fprintf (stderr, "D%X ", dibit); - //fprintf (stderr, "P%X ", state->dmr_stereo_payload[i]); - if(i == 2) - { - state->currentslot = (1 & (dibit >> 1)); - internalslot = (1 & (dibit >> 1)); - } + + cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1 + cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 } + cachdata[25] = 0; //setting to see if this fixes ubuntu 32 bit bug + + //decode and correct cach and compare + int cach_okay = 69; + if ( Hamming_7_4_decode (cachdata) ) //see if we need to de-interleave this...probably do. + { + cach_okay = 1; + } + if (cach_okay == 1) + { + //fprintf (stderr, "CACH Okay "); + } + if (cach_okay != 1) + { + //fprintf (stderr, "CACH FEC Error %d", cach_okay); + } + + state->currentslot = cachdata[1]; + internalslot = cachdata[1]; + + //this cach fec seems to work quite well, really helps on shaky signals + //Setup for first AMBE Frame //Interleave Schedule w = rW; @@ -140,19 +160,24 @@ void dmrBS (dsd_opts * opts, dsd_state * state) //short int l = 0; //do I still use this? // signaling data or sync + long long int late_entry_pi[24] = {0}; + short int m = 0; for(i = 0; i < 24; i++) { dibit = getDibit(opts, state); state->dmr_stereo_payload[i+66] = dibit; syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1 - syncdata[(2*i)+1] = (1 & dibit); // bit 0 + syncdata[(2*i)+1] = (1 & dibit); // bit 0 sync[i] = (dibit | 1) + 48; - if (i < 4 || i > 19) // + if (i < 4 || i > 19) { - EmbeddedSignalling[2*i] = (1 & (dibit >> 1)); // bit 1 - EmbeddedSignalling[2*i+1] = (1 & dibit); // bit 0 + // fprintf(stderr, "\n EMB = "); + EmbeddedSignalling[(2*i)] = (1 & (dibit >> 1)); // bit 1 + //fprintf (stderr, "%02b", dibit); + EmbeddedSignalling[(2*i)+1] = (1 & dibit); // bit 0 + } //Used for ProcessVoiceBurstSync @@ -168,6 +193,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) 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; @@ -194,9 +220,20 @@ void dmrBS (dsd_opts * opts, dsd_state * state) state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]); state->LCSS_ok = EmbeddedSignallingOk; - } - else skipcount++; + for (i = 0; i < 8; i++) + { + //fprintf (stderr, " %b", EmbeddedSignalling[i]); + } + } + //else skipcount++; + else + { + for (i = 0; i < 8; i++) + { + //fprintf (stderr, " %b", EmbeddedSignalling[i]); + } + } //Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling for(i = 0; i < 18; i++) { @@ -248,15 +285,27 @@ void dmrBS (dsd_opts * opts, dsd_state * state) if (internalslot == 0) { vc1 = 1; - state->dropL = 256; } if (internalslot == 1) { vc2 = 1; - state->dropR = 256; } } + // if( strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) + // { + // fprintf (stderr,"%s ", getTime()); + // fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 1 \n"); + // goto SKIP; + // } + // + // if( strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) + // { + // fprintf (stderr,"%s ", getTime()); + // fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 2 \n"); + // goto SKIP; + // } + //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 ) { @@ -273,7 +322,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) else fprintf (stderr,"Sync: -DMR "); //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame vc1 = 1; - //state->dropL = 256; + } if (internalslot == 1) { @@ -287,7 +336,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) else fprintf (stderr,"Sync: -DMR "); //constantly reset the vc counter to 1 each data frame in anticipation of new voice frame vc2 = 1; - //state->dropR = 256; + } processDMRdata (opts, state); skipcount++; //after 2 data frames, drop back to getFrameSync and process subsequent data with processDMRdata @@ -304,6 +353,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) //only play voice on no data sync if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) { + if (EmbeddedSignallingOk == 0) { //goto END; @@ -314,7 +364,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) if (internalslot == 0) { state->dmrburstL = 16; //use 16 for Voice? - //fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | VC%d \n", state->dmr_color_code, vc1); + if (opts->inverted_dmr == 0) { fprintf (stderr,"Sync: +DMR [SLOT1] slot2 | | DMRSTEREO | VC%d ",vc1); @@ -324,11 +374,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - //the condition below should be swapped to vc6 and not on vc1, placement after processMbeFrame - if (vc1 == 1 && state->payload_algid != 0 && opts->payload == 1) - { - //LFSR(state); //placement here causes issues when second slot becomes active as well - } fprintf (stderr, "\n"); } else @@ -340,11 +385,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - //the condition below should be swapped to vc6 and not on vc1, placement after processMbeFrame - if (vc1 == 1 && state->payload_algid != 0 && opts->payload == 1) - { - //LFSR(state); //placement here causes issues when second slot becomes active as well - } fprintf (stderr, "\n"); } } @@ -361,11 +401,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - //the condition below should be swapped to vc6 and not on vc1, placement after processMbeFrame - if (vc2 == 1 && state->payload_algidR != 0 && opts->payload == 1) - { - //LFSR(state); - } fprintf (stderr, "\n"); } else @@ -377,11 +412,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - //the condition below should be swapped to vc6 and not on vc1, placement after processMbeFrame - if (vc2 == 1 && state->payload_algidR != 0 && opts->payload == 1) - { - //LFSR(state); - } fprintf (stderr, "\n"); } } @@ -403,29 +433,31 @@ void dmrBS (dsd_opts * opts, dsd_state * state) processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - //We only want to run LFSR after processing VC6 frames and before rolling - //back to VC1, otherwise we will incur an unwanted LFSR if voice becomes active - //in both slots while in this loop if (internalslot == 0 && vc1 == 6) { - state->dropL = 256; - if (state->payload_algid != 0 ) //&& opts->payload == 1 + + if (state->payload_algid >= 0x21) { - LFSR(state); + //running this as state->payload_mi > 0 apparently causes some problem, don't know why + if (state->payload_mi != 0 && state->payload_algid >= 0x21) + { + LFSR(state); + } fprintf (stderr, "\n"); } - } if (internalslot == 1 && vc2 == 6) { - state->dropR = 256; - if (state->payload_algidR != 0 ) //&& opts->payload == 1 + + if (state->payload_algidR >= 0x21) { - LFSR(state); + if (state->payload_miR != 0 && state->payload_algidR == 0x21) + { + LFSR(state); //re-enable this one after testing Late Entry MI + } fprintf (stderr, "\n"); } - } if (internalslot == 0) @@ -436,6 +468,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state) { vc2++; } + } // recalibrate center/umid/lmid, not sure this helps or does anything particularly in this case @@ -677,10 +710,6 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state) fprintf (stderr, "\n"); } - //these ambe_fr values are set correctly now! - //reset drop values since we don't know which slot (because I'm too lazy to write that part) - state->dropL = 256; - state->dropR = 256; processMbeFrame (opts, state, NULL, ambe_fr, NULL); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); diff --git a/src/dmr_data.c b/src/dmr_data.c index f8429c1..2c6b709 100644 --- a/src/dmr_data.c +++ b/src/dmr_data.c @@ -25,14 +25,17 @@ processDMRdata (dsd_opts * opts, dsd_state * state) int *dibit_p; char sync[25]; char syncdata[48]; - char cachdata[13] = {0}; + char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug char cc[5] = {0}; char ccAscii[5] = {0}; char bursttype[5]; unsigned int burst; char info[196]; - char SlotType[20]; + // char SlotType[20]; //was char, but I don't think FEC brings back good values when usign that + unsigned char SlotType[20]; //was char, but I don't think FEC brings back good values when usign that unsigned int SlotTypeOk; + int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + /* Remove warning compiler */ //UNUSED_VARIABLE(cachdata[0]); @@ -57,7 +60,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) dibit_p = state->dmr_payload_p - 90; } - // CACH + // CACH, why aren't we running any FEC on this? for (i = 0; i < 12; i++) { dibit = *dibit_p; @@ -71,31 +74,72 @@ processDMRdata (dsd_opts * opts, dsd_state * state) dibit = (int)state->dmr_stereo_payload[i]; } //fprintf(stderr, "%X", dibit); - cachdata[i] = dibit; + //cachdata[i] = dibit; + + cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1 + cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 + // cachdata[(i*2)] = (1 & (dibit >> 1)); // bit 1 + // cachdata[(i*2)+1] = (1 & dibit); // bit 0 + if (i == 2) { /* Change the current slot only if we are in relayed mode (not in direct mode) */ - if(state->directmode == 0) state->currentslot = (1 & (dibit >> 1)); // bit 1 - - if (state->currentslot == 0 && state->dmr_ms_mode == 0) - { - state->slot1light[0] = '['; - state->slot1light[6] = ']'; - state->slot2light[0] = ' '; - state->slot2light[6] = ' '; - } - //else - if (state->currentslot == 1 && state->dmr_ms_mode == 0) - { - state->slot2light[0] = '['; - state->slot2light[6] = ']'; - state->slot1light[0] = ' '; - state->slot1light[6] = ' '; - } + // if(state->directmode == 0) state->currentslot = (1 & (dibit >> 1)); //move this until after cach fec performed + // + // if (state->currentslot == 0 && state->dmr_ms_mode == 0) + // { + // state->slot1light[0] = '['; + // state->slot1light[6] = ']'; + // state->slot2light[0] = ' '; + // state->slot2light[6] = ' '; + // } + // //else + // if (state->currentslot == 1 && state->dmr_ms_mode == 0) + // { + // state->slot2light[0] = '['; + // state->slot2light[6] = ']'; + // state->slot1light[0] = ' '; + // state->slot1light[6] = ' '; + // } } } - cachdata[12] = 0; + //cachdata[12] = 0; + cachdata[25] = 0; //setting to see if this fixes ubuntu 32 bit bug + //decode and correct cach and compare + int cach_okay = 69; + if ( Hamming_7_4_decode (cachdata) ) //is now de-interleaved appropriately + { + cach_okay = 1; + } + if (cach_okay == 1) + { + //fprintf (stderr, "CACH Okay "); + } + if (cach_okay != 1) + { + //fprintf (stderr, "CACH FEC Error %d", cach_okay); + goto END; + } + + state->currentslot = cachdata[1]; //still bit 2, or somewhere else? is it 8? 1? TC? + + if (state->currentslot == 0 && state->dmr_ms_mode == 0) + { + state->slot1light[0] = '['; + state->slot1light[6] = ']'; + state->slot2light[0] = ' '; + state->slot2light[6] = ' '; + } + //else + if (state->currentslot == 1 && state->dmr_ms_mode == 0) + { + state->slot2light[0] = '['; + state->slot2light[6] = ']'; + state->slot1light[0] = ' '; + state->slot1light[6] = ' '; + } + //end correct cach and set slot #ifdef DMR_DUMP k = 0; @@ -232,7 +276,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) syncdata[(2*i)+1] = (1 & dibit); // bit 0 sync[i] = (dibit | 1) + 48; } - sync[24] = 0; + sync[24] = 0; //why? #ifdef DMR_DUMP k = 0; @@ -296,8 +340,18 @@ processDMRdata (dsd_opts * opts, dsd_state * state) } /* Check and correct the SlotType (apply Golay(20,8) FEC check) */ - if(Golay_20_8_decode((unsigned char *)SlotType)) SlotTypeOk = 1; - else SlotTypeOk = 0; + //pretty sure this isn't working correcty, does not apply corrected bits, due to cast type mismatching + // if(Golay_20_8_decode((unsigned char *)SlotType)) SlotTypeOk = 1; + if( Golay_20_8_decode(SlotType) ) + { + SlotTypeOk = 1; + //fprintf (stderr, "Slot Okay "); + } + else + { + SlotTypeOk = 0; + goto END; + } /* Slot Type parity checked => Fill the color code */ //state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]); @@ -469,14 +523,14 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = MBC Header */ case 0b0100: { - //ProcessMBChData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + ProcessMBChData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = MBC Continuation*/ case 0b0101: { - //ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -512,14 +566,14 @@ processDMRdata (dsd_opts * opts, dsd_state * state) /* Burst = Rate 1 DATA */ case 0b1010: { - //Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } /* Burst = Unified Single Block DATA */ case 0b1101: { - //ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } @@ -527,7 +581,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state) default: { /* Nothing to do */ - //ProcessWTFData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); + ProcessReservedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType); break; } } /* End switch(burst) */ @@ -536,5 +590,13 @@ processDMRdata (dsd_opts * opts, dsd_state * state) { fprintf(stderr, "\n"); } - //JUMP: + END: + if (SlotTypeOk == 0 || cach_okay == 0) + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, " **CACH or Burst Type FEC ERR - SKIPPING** "); + fprintf (stderr, "%s", KNRM); + fprintf (stderr, "\n"); + } + } /* End processDMRdata() */ diff --git a/src/dmr_ms.c b/src/dmr_ms.c index bdb5609..10e93c8 100644 --- a/src/dmr_ms.c +++ b/src/dmr_ms.c @@ -33,6 +33,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state) 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 @@ -60,12 +61,15 @@ void dmrMS (dsd_opts * opts, dsd_state * state) short int skipcount = 0; //Hardset variables for MS - state->currentslot = 0; + state->currentslot = 0; //0 internalslot = 0; activeslot = 0; //Run Loop while the getting is good while (loop == 1) { + + short int m = 0; + state->dmrburstL = 16; //Use 16 for Voice? // No CACH in MS Mode? for(i = 0; i < 12; i++) @@ -258,17 +262,9 @@ void dmrMS (dsd_opts * opts, dsd_state * state) 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) ) - //fixed to compensate for inverted signal if ( ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) && opts->inverted_dmr == 0) || ((strcmp (sync, DMR_MS_DATA_SYNC) == 0) && opts->inverted_dmr == 1) ) @@ -276,29 +272,18 @@ void dmrMS (dsd_opts * opts, dsd_state * state) if (internalslot == 0) { vc1 = 1; - state->dropL = 256; fprintf (stderr, "MS Slot 1 Voice Sync \n"); - //activeslot = 0; - } + if (internalslot == 1) { vc2 = 1; - state->dropR = 256; - //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 @@ -370,9 +355,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state) 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) - //fixed to compensate for inverted signal if( ( ( ((strcmp (sync, DMR_MS_DATA_SYNC) != 0) && opts->inverted_dmr == 0) || ((strcmp (sync, DMR_MS_VOICE_SYNC) != 0) && opts->inverted_dmr == 1) ) ) && internalslot == activeslot && vc1 < 7) @@ -390,10 +372,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - if (vc1 == 6 && state->payload_algid != 0 && opts->payload == 1) - { - LFSR(state); - } fprintf (stderr, "\n"); } @@ -406,67 +384,32 @@ void dmrMS (dsd_opts * opts, dsd_state * state) fprintf(stderr, " BPK %lld", state->K); fprintf (stderr, "%s", KNRM); } - if (vc1 == 6 && state->payload_algid != 0 && opts->payload == 1) - { - LFSR(state); - } fprintf (stderr, "\n"); } - if (internalslot == 1 && opts->inverted_dmr == 0) - { - fprintf (stderr,"Sync: +DMR MS MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc2); - if (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); - } - if (vc2 == 6 && state->payload_algidR != 0 && opts->payload == 1) - { - LFSR(state); - } - fprintf (stderr, "\n"); - } - if (internalslot == 1 && opts->inverted_dmr == 1) - { - fprintf (stderr,"Sync: -DMR MS MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc2); - if (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); - } - if (vc2 == 6 && state->payload_algidR != 0 && opts->payload == 1) - { - LFSR(state); - } - fprintf (stderr, "\n"); - } + 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"); - } + state->dmr_ms_mode == 1; processMbeFrame (opts, state, NULL, ambe_fr, NULL); processMbeFrame (opts, state, NULL, ambe_fr2, NULL); processMbeFrame (opts, state, NULL, ambe_fr3, NULL); - if (internalslot == 0) + + //need to seperate the algs here so we don't run LFSR on 22 and so on + if (vc1 == 6 && state->payload_algid >= 21) { - //vc1++; - } - if (internalslot == 1) - { - vc2++; - } + //state->currentslot = 0; + if (state->payload_mi != 0 && state->payload_algid >= 0x21) + { + LFSR(state); + } + fprintf (stderr, "\n"); + } } vc1++; //6 seems optimal for MS, allows to quickly exit and resync if wonky or something @@ -692,13 +635,13 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) } fprintf (stderr, "\n"); } - //reset drop values since we don't know which slot (because I'm too lazy to write that part) - state->dropL = 256; - state->dropR = 256; + state->dmr_ms_mode = 1; + 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 @@ -706,11 +649,17 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state) void dmrMSData (dsd_opts * opts, dsd_state * state) { - int i; + int i, b, c; int dibit; int *dibit_p; unsigned int burst; + unsigned char MSCach[24] = {0}; //12 dibits = 24 bits + unsigned char MSSync[48] = {0}; //24 dibits = 48 bits + unsigned char MSSlot[20] = {0}; //10 dibits = 20 bits + unsigned char MSBurst[5] = {0}; + int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23}; + //int cachInterleave[24] = {0,} //add time to mirror sync time_t now; char * getTime(void) //get pretty hh:mm:ss timestamp @@ -727,7 +676,8 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) return curr; } - + b = 0; + c = 0; //CACH + First Half Payload + Sync = 12 + 54 + 24 //dibit_p = state->dibit_buf_p - 90; dibit_p = state->dmr_payload_p - 90; @@ -740,14 +690,42 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) dibit = (dibit ^ 2); } state->dmr_stereo_payload[i] = dibit; + //load cach + if (i < 12) + { + MSCach[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1 + MSCach[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0 + } + //load slot, first half + if (i > 60 && i < 66) + { + MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1 + MSSlot[(b*2)+1] = (1 & dibit); // bit + b++; + } + //load sync + if (i > 66) + { + MSSync[(c*2)] = (1 & (dibit >> 1)); // bit 1 + MSSync[(c*2)+1] = (1 & dibit); // bit 0 + c++; + } } for (i = 0; i < 54; i++) { dibit = getDibit(opts, state); state->dmr_stereo_payload[i+90] = dibit; + //load slot, second half + if (i < 6) + { + MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1 + MSSlot[(b*2)+1] = (1 & dibit); // bit + b++; + } } + //hide behind payload due to errs in data in MS mode if (opts->payload == 1) { @@ -775,9 +753,6 @@ void dmrMSData (dsd_opts * opts, dsd_state * state) state->dmr_stereo = 0; state->dmr_ms_mode = 0; - //reset drop values since we don't know which slot (because I'm too lazy to write that part) - state->dropL = 256; - state->dropR = 256; //get potential first half payload dibits and store them in the payload for the next repitition, MS voice or data. skipDibit (opts, state, 144); diff --git a/src/dmr_process_voice.c b/src/dmr_process_voice.c index 909f11d..9a57aef 100644 --- a/src/dmr_process_voice.c +++ b/src/dmr_process_voice.c @@ -19,10 +19,6 @@ #include "dmr_const.h" #include "p25p1_check_hdu.h" -// -//A -// - void ProcessDMR (dsd_opts * opts, dsd_state * state) { uint32_t i, j; @@ -40,7 +36,6 @@ void ProcessDMR (dsd_opts * opts, dsd_state * state) 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, @@ -75,9 +70,8 @@ int BP[256] = { 0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3, 0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255 }; -// -//H -// + + if (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) { fprintf (stderr, "%s", KYEL); @@ -85,12 +79,12 @@ if (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->pa 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++) + for(j = 0; j < 48; j++) { x = ( ((k << j) & 0x800000000000) >> 47 ); TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; @@ -111,7 +105,7 @@ if (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->p { for(i = 0; i < 3; i++) { - for(j = 0; j < 49; j++) + for(j = 0; j < 48; j++) { x = ( ((k << j) & 0x800000000000) >> 47 ); TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x; @@ -119,15 +113,10 @@ if (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->p } } } -// -//B -// + if (state->currentslot == 0) { - if (opts->payload == 1 && state->R == 0) - { - fprintf(stderr, "\n"); //line break for AMBE printer - } + for(Frame = 0; Frame < 6; Frame++) //6 { /* 1 DMR frame contains 3 AMBE voice samples */ @@ -147,35 +136,43 @@ if (state->currentslot == 0) PrintAMBEData(opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); } - if (opts->mbe_out_f != NULL) + //quick enc toggle to determine whether or not to play enc traffic + int enc_bit = 0; + enc_bit = (state->dmr_so >> 6) & 0x1; + if (enc_bit == 1) { - saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + state->dmr_encL = 1; } - - state->debug_audio_errors += *errs2; - - processAudio(opts, state); - - if (opts->wav_out_f != NULL) + else state->dmr_encL = 0; + //quick test to determine whether or not to run the next few steps below + if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) { - writeSynthesizedVoice (opts, state); - } + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + } - //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); - } + state->debug_audio_errors += *errs2; + + processAudio(opts, state); + + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } + + if (opts->audio_out == 1) //opts->audio_out == 1 + { + playSynthesizedVoice (opts, state); + } + } //second bracket for the test enc condition } /* End for(i = 0; i < 3; i++) */ } /* End for(Frame = 0; Frame < 6; Frame++) */ } //End if Current Slot == 0 if (state->currentslot == 1) { - if (opts->payload == 1) - { - fprintf(stderr, "\n"); //line break for AMBE printer - } + for(Frame = 0; Frame < 6; Frame++) { /* 1 DMR frame contains 3 AMBE voice samples */ @@ -196,24 +193,36 @@ if (state->currentslot == 0) PrintAMBEData(opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); } - if (opts->mbe_out_f != NULL) + //quick enc toggle to determine whether or not to play enc traffic + int enc_bit = 0; + enc_bit = (state->dmr_soR >> 6) & 0x1; + if (enc_bit == 1) { - saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + state->dmr_encR = 1; } + else state->dmr_encR = 0; - state->debug_audio_errors += *errs2; - - processAudio(opts, state); - - if (opts->wav_out_f != NULL) + //quick test to determine whether or not to run the next few steps below + if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) { - writeSynthesizedVoice (opts, state); - } + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]); + } - //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); + state->debug_audio_errors += *errs2; + + processAudio(opts, state); + + if (opts->wav_out_f != NULL) + { + writeSynthesizedVoice (opts, state); + } + + if (opts->audio_out == 1) + { + playSynthesizedVoice (opts, state); + } } } /* End for(i = 0; i < 3; i++) */ } /* End for(Frame = 0; Frame < 6; Frame++) */ diff --git a/src/dmr_sync.c b/src/dmr_sync.c index 7a85988..7e78da1 100644 --- a/src/dmr_sync.c +++ b/src/dmr_sync.c @@ -17,16 +17,38 @@ #include "dsd.h" -//#define PRINT_PI_HEADER_BYTES -//#define PRINT_VOICE_LC_HEADER_BYTES -//#define PRINT_TERMINAISON_LC_BYTES -//#define PRINT_VOICE_BURST_BYTES +char * getTimeL(void) //get pretty hh:mm:ss timestamp +{ + time_t t = time(NULL); -//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 + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; +} + +//getDate has a bug that affects writing to file using fopen 32-bit Ubuntu OS, need to look into +char * getDateL(void) { + char datename[99]; //increased to 99 to fix 32-bit Ubuntu when fopen file printing to lrrp.txt + char * curr2; + struct tm * to; + time_t t; + t = time(NULL); + to = localtime( & t); + strftime(datename, sizeof(datename), "%Y/%m/%d", to); + curr2 = strtok(datename, " "); + return curr2; +} + +//Trellis Decoding still needs work, so don't be surprised by bad decodes void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]) { - //NEED TRELLIS DECODER HERE + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -51,48 +73,218 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] TSVoiceSupFrame = &state->TS2SuperFrame; } - CRCExtracted = 0; - CRCComputed = 0; - IrrecoverableErrors = 0; - - /* Deinterleave DMR data */ - //BPTCDeInterleaveDMRData(info, DeInteleavedData); - //info is the dibits; is output DeInterleavedData? - //data is dibits I think, so sub info for data? only wants 98U dibits though. - //returns 'payload' which is 144 bit array, so DmrDataBit maybe? - //CDMRTrellisDecode(const unsigned char* data, unsigned char* payload) unsigned char tdibits_reverse[98]; unsigned char tdibits_inverted[98]; unsigned char tdibits_to_bits[196]; - if (1 == 2) - { - //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]); - } - } - //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_reverse, TrellisReturn); //NEEDS REVERSE DIBITS! + + for(i = 0, j = 0; i < 18; i++, j+=8) + { + DmrDataBit[j + 0] = (TrellisReturn[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (TrellisReturn[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (TrellisReturn[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (TrellisReturn[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (TrellisReturn[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (TrellisReturn[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (TrellisReturn[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (TrellisReturn[i] >> 0) & 0x01; + } + + //define our block and padding values + uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below + uint8_t padding = state->data_header_padding[slot]; + + //shift data in the superframe up a block + k = 0; + for(i = 0; i < 16; i++) //16, or 18? seems to have two extra bytes in front currently + { + state->dmr_34_rate_sf[slot][i] = state->dmr_34_rate_sf[slot][i+16]; + state->dmr_34_rate_sf[slot][i+16] = state->dmr_34_rate_sf[slot][i+32]; + state->dmr_34_rate_sf[slot][i+32] = state->dmr_34_rate_sf[slot][i+48]; + state->dmr_34_rate_sf[slot][i+48] = state->dmr_34_rate_sf[slot][i+64]; + state->dmr_34_rate_sf[slot][i+64] = state->dmr_34_rate_sf[slot][i+80]; + + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + k++; + } + + state->dmr_34_rate_sf[slot][i+(blocks*16)] = TrellisReturn[i+2]; //plus two to skip the first two bytes + } + + //Start Polling the 3/4 Rate Super Frame for Data when byte 0 contains values + //LRRP + int message_legnth = 0; + if ( (state->dmr_34_rate_sf[slot][0] & 0x7F) == 0x45) //Start LRRP now + { + + //find user home directory and append directory and filename. + FILE * pFile; //put this outside of the if statement? + if (opts->lrrp_file_output == 1) + { + char * filename = "/lrrp.txt"; + char * home_dir = getenv("HOME"); + char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1); + strncpy (filepath, home_dir, strlen(home_dir) + 1); + strncat (filepath, filename, strlen(filename) + 1); + //end find user home directory and append directory and filename + + pFile = fopen (filepath, "a"); + + //hard code filename override for those wanting to use other software + //pFile = fopen("DSDPlus.LRRP", "a"); + + fprintf (pFile, "%s\t %s\t", getDateL(), getTimeL()); //current timestamp, may find a way to only add this IF no included timestamp in LRRP data? + fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header + } + + + fprintf (stderr, "%s ", KMAG); + + //go to number of octets minus padding and crc, confirmed data may need a second rule to skip Serial Numbers and Block CRCs + for (short i = 12; i < ( ((blocks+1)*16) - (padding+4) ); i++) + { + + 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]); + + i = i + 12; //skip 12 bytes here so we don't accidentally trip another flag with data in these bytes + } + + if (state->dmr_34_rate_sf[slot][i] == 0x0D) //This should lock on to the second 0x0D value hopefully and tell us the message legnth + { + message_legnth = state->dmr_34_rate_sf[slot][i+1]; + fprintf (stderr, "\n Message Legnth: %02d", message_legnth); + i = i + 2; //skip 2 bytes here so we don't accidentally trip another flag with data in these bytes + } + + if ( state->dmr_34_rate_sf[slot][i] == 0x34 && message_legnth > 27 ) //timestamp, seems to need legnth of 28 + { + fprintf (stderr, "\n LRRP - Timestamp: "); + 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 + + i = i + 6; //skip 6 bytes here so we don't accidentally trip another flag with data in these bytes + } + + if ( state->dmr_34_rate_sf[slot][i] == 0x51 && message_legnth > 13) //lattitude and longitude, message_lenght > 13? + { + fprintf (stderr, "\n LRRP -"); + fprintf (stderr, " Lat: "); + if (state->dmr_34_rate_sf[slot][i+1] & 0x80) //first bit indicates a sign, or hemisphere? + { + fprintf (stderr, "-"); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "-"); + } + } + long int lrrplat; + long int lrrplon; + double lat_unit = (double)180/(double)4294967295; + double lon_unit = (double)360/(double)4294967295; + 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); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.5lf\t", ((double)lrrplat) * lat_unit); + } + fprintf (stderr, " Lon: "); + if (state->dmr_34_rate_sf[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? + { + //fprintf (stderr, "-"); + } + fprintf (stderr, "%.5lf", (lrrplon * lon_unit) ); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.5lf\t", (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) ); + } + else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + + i = i + 9 + 2; //skip 9 bytes here so we don't accidentally trip another flag with data in these bytes + } + + + if ( state->dmr_34_rate_sf[slot][i] == 0x6C && message_legnth > 13) + { + //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. double check double values? + //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[slot][i+1] ) + state->dmr_34_rate_sf[slot][i+2] )) / ( (double)128)); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.3lf\t ", (velocity * 3.6) ); + } + fprintf (stderr, "\n LRRP - Velocity: %.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)); + + i = i + 3; //skip 3 bytes here so we don't accidentally trip another flag with data in these bytes + } + if ( state->dmr_34_rate_sf[slot][i] == 0x56 && message_legnth > 13) + { + //check for appropriate terminology here - Heading, bearing, course, or track? + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%d\t", state->dmr_34_rate_sf[slot][i+1] * 2); + } + fprintf (stderr, "\n LRRP - Track: %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); + + //i = ((blocks+1)*12); //skip to end of loop here so we don't accidentally trip another flag with data in these bytes + i = 99; + } + //try for a Control ACK at the very end if nothing else pops, flag still unknown + if ( (state->dmr_34_rate_sf[slot][i] == 0x36 || state->dmr_34_rate_sf[slot][i] == 0x37) && message_legnth > 6 ) + { + fprintf (stderr, "\n LRRP - Control ACK "); + } + } + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "\n"); + fclose (pFile); + } + } + fprintf (stderr, "%s ", KNRM); + + //Full 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, "\n Full 3/4 Rate Trellis Payload - Slot [%d]\n ", slot+1); + for (i = 0; i < 18; i++) //16, or 18? { fprintf (stderr, "[%02X]", TrellisReturn[i]); } @@ -107,245 +299,42 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] } fprintf (stderr,"%s", KNRM); //change back to normal } - /* Extract the BPTC 196,96 DMR data */ - //IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); - // - //CDMRTrellisDibitsToPoints(const signed char* dibits, unsigned char* points) ?? - // - /* 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; - DmrDataBit[j + 1] = (TrellisReturn[i] >> 6) & 0x01; - DmrDataBit[j + 2] = (TrellisReturn[i] >> 5) & 0x01; - DmrDataBit[j + 3] = (TrellisReturn[i] >> 4) & 0x01; - DmrDataBit[j + 4] = (TrellisReturn[i] >> 3) & 0x01; - DmrDataBit[j + 5] = (TrellisReturn[i] >> 2) & 0x01; - 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; - DmrDataBit[j + 1] = (TrellisReturn[17-i] >> 1) & 0x01; - DmrDataBit[j + 2] = (TrellisReturn[17-i] >> 2) & 0x01; - DmrDataBit[j + 3] = (TrellisReturn[17-i] >> 3) & 0x01; - DmrDataBit[j + 4] = (TrellisReturn[17-i] >> 4) & 0x01; - DmrDataBit[j + 5] = (TrellisReturn[17-i] >> 5) & 0x01; - 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 < 16; i++) //16, or 18? seems to have two extra bytes in front currently - { - 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++) - { - DmrDataByte[i] = DmrDataByte[i] << 1; - //DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); - 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]& 0xFF; - state->dmr_34_rate_sf[slot][i+48] = TrellisReturn[i+2]; //plus two to skip the first two bytes - } - if (opts->payload == 2) + //Full Super Frame - Debug Output + if (opts->payload == 1 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) { fprintf (stderr, "%s",KGRN); fprintf (stderr, "\n Rate 3/4 Superframe - Slot [%d]\n ",slot+1); - for (i = 0; i < (16*4); i++) + for (i = 0; i < ((blocks+1)*16); i++) //(16*4), using 16 since we jump the first two bytes { fprintf (stderr, "[%02X]", state->dmr_34_rate_sf[slot][i]); - if (i == 15 || i == 31 || i == 47) + if (i == 15 || i == 31 || i == 47 || i == 63 || i == 79) { 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++) - 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 - } - - //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; - - /* 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); - - // - /* 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"); - } - - if ( (state->dmr_34_rate_sf[0] & 0x3F) == 0x0C) - { - fprintf (stderr, "\n Source: "); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[0] & 0x3F), state->dmr_34_rate_sf[1], state->dmr_34_rate_sf[2], state->dmr_34_rate_sf[3]); //strip first two bits off 1st byte - fprintf (stderr, " [%08d]", (state->dmr_34_rate_sf[1] <<16 ) + (state->dmr_34_rate_sf[2] << 8) + state->dmr_34_rate_sf[3] ); - fprintf (stderr, " - Port %05d", (state->dmr_34_rate_sf[8] << 8) + state->dmr_34_rate_sf[9]); - fprintf (stderr, "\n Destination:"); - fprintf (stderr, " %03d.%03d.%03d.%03d", (state->dmr_34_rate_sf[4] & 0x3F), state->dmr_34_rate_sf[5], state->dmr_34_rate_sf[6], state->dmr_34_rate_sf[7]); //strip first two bits off 4th byte?? - 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]); - } - */ - //temp hide behind payload until working better - if (opts->payload == 1) - { - //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[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[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[slot][i] == 0x51 ) //lattitude and longitude - { - fprintf (stderr, "\n LRRP -"); - fprintf (stderr, " Lat: "); - if (state->dmr_34_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_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[slot][i+5] & 0x80) //first bit indicates a sign, or hemisphere? - { - //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[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[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[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[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)\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); - } - } - + state->data_block_counter[state->currentslot]++; //increment block counter } -//This is Data Header, why did I name it Data Data +//This is Data Header 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; + //see if we still need this portion if we are going to use the data block info //clear out the 3/4 rate data superframe so we don't repeat old info - for (short int i = 0; i < (16*4); i++) + for (short int i = 0; i < 288; i++) //expanded to 288 to prevent crashing { 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++) + for (short int i = 0; i < 288; i++) //expanded to 288 to prevent crashing { state->dmr_12_rate_sf[slot][i] = 0; } - //Placeholder uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -358,13 +347,6 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint uint8_t R[3]; uint8_t BPTCReservedBits = 0; - // Extract parameters for logging purposes - uint8_t csbk_lb = 0; - uint8_t csbk_pf = 0; - uint8_t csbk_o = 0; - uint8_t csbk_fid = 0; - uint64_t csbk_data = 0; - uint8_t csbk = 0; /* Check the current time slot */ if(state->currentslot == 0) @@ -404,23 +386,17 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ CRCExtracted = 0; - //for(i = 0; i < 24; i++) 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 + 80] & 1); } - //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 ^ 0xCCCC; /* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */ CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0xCCCC); - //CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969); /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -446,32 +422,172 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint } else {}//fprintf (stderr, ("\n(Data CRC Fail, FEC Fail)")); - // + //collect relevant data header info, figure out format, and grab appropriate info from it + if (state->data_p_head[state->currentslot] == 0) + { + fprintf (stderr, "%s ", KGRN); + state->data_block_counter[state->currentslot] = 1; //reset block counter to 1 + state->data_header_format[state->currentslot] = DmrDataByte[0]; //collect the entire byte, we can check group or individual, response requested as well on this + state->data_header_sap[state->currentslot] = (DmrDataByte[1] & 0xF0) >> 4; //SAP is IP(4) or other + + // state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block + // state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data + // fprintf (stderr, "\n Unconfirmed Data Header: Format %02X - SAP %02X - Block Count %02X - Padding Octets %02X", + // state->data_header_format[state->currentslot], state->data_header_sap[state->currentslot], + // state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); + + if ( (state->data_header_format[state->currentslot] & 0xF) == 0x2) + { + state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block + state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data + fprintf (stderr, "\n Unconfirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", + state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], + state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF) == 0x3) + { + state->data_header_padding[state->currentslot] = DmrDataByte[1] & 0xF; //number of padding octets on last block + state->data_header_blocks[state->currentslot] = DmrDataByte[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data + fprintf (stderr, "\n Confirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X", + state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], + state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF) == 0xD) //DD_HEAD + { + state->data_header_padding[state->currentslot] = DmrDataByte[7] & 0xF; + state->data_header_blocks[state->currentslot] = ( (DmrDataByte[0] & 0x30) | ((DmrDataByte[1] & 0xF) >> 0) ); //what a pain MSB | LSB + fprintf (stderr, "\n Short Data - Defined: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", + state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], + state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF) == 0xE) //SP_HEAD or R_HEAD + { + state->data_header_padding[state->currentslot] = DmrDataByte[7] & 0xF; + state->data_header_blocks[state->currentslot] = ( (DmrDataByte[0] & 0x30) | ((DmrDataByte[1] & 0xF) >> 0) ); //what a pain MSB | LSB + fprintf (stderr, "\n Short Data - Raw or Precoded: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X", + state->data_header_format[state->currentslot] & 0xF, state->data_header_sap[state->currentslot], + state->data_header_blocks[state->currentslot], state->data_header_padding[state->currentslot] ); + } + + + } + + //sanity check to prevent random crash in 1/2 rate and 3/4 rate data + //we want to assign extra large block sizes to a max of 7 so we don't overload the 1/2 or 3/4 array + if (state->data_header_blocks[state->currentslot] > 7) + { + state->data_header_blocks[state->currentslot] = 7; //currently 1/2 only supports a max of 7 blocks per slot + } + + + //set source here so we can reference it in our text dump + state->dmr_lrrp_source[state->currentslot] = (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]; + fprintf (stderr, "%s ", KNRM); + //end collecting data header info + fprintf (stderr, "%s ", KMAG); - if (DmrDataByte[0] == 0x43) + if (state->data_header_sap[state->currentslot] == 0x4 && state->data_p_head[state->currentslot] == 0) //4 is IP data { - fprintf (stderr, "\n IP4 Source IP:"); - fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not - fprintf (stderr, "[%d]", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - fprintf (stderr, " Destination IP:"); - 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] ); + fprintf (stderr, "\n IP4 Data - Source: "); + //fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); + fprintf (stderr, " Destination: "); + //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); + + //part below should probably be inside of above if condition + if (1 == 1) //already setting by current slot, no need for checking first + { + sprintf ( state->dmr_lrrp[state->currentslot][1], "SRC [%d] DST [%d] ", + ( (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7]), + ( (DmrDataByte[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4]) ); + } + } - if (1 == 1) //already setting by current slot, no need for checking first + + if (state->data_header_sap[state->currentslot] == 0x5 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol { - 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]) ); + fprintf (stderr, "\n ARP - Address Resolution Protocol "); } - if (DmrDataByte[0] == 0x01) + + if ( (state->data_header_format[state->currentslot] & 0xF ) == 0xD && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol { - fprintf (stderr, "\n LRRP Control ACK - "); + fprintf (stderr, "\n Short Data - Defined - Source: "); + //fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); + fprintf (stderr, " Destination: "); + //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF) == 0xE && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol + { + fprintf (stderr, "\n Short Data - Raw or Status/Precoded - Source: "); + //fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); + fprintf (stderr, " Destination: "); + //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF ) == 0x1 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol + { + fprintf (stderr, "\n Response Packet - Source: "); + //fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); + fprintf (stderr, " Destination: "); + //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); + } + + if ( (state->data_header_format[state->currentslot] & 0xF ) == 0x0 && state->data_p_head[state->currentslot] == 0) //5 is ARP Address Resolution Protocol + { + fprintf (stderr, "\n Unified Data Transport - Source: "); + //fprintf (stderr, " %d.%d.%d.%d", (DmrDataByte[0] & 0x3F), DmrDataByte[1], DmrDataByte[2], DmrDataByte[3]); //not sure if these are right or not + fprintf (stderr, "[%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] << 8) + DmrDataByte[7] ); + fprintf (stderr, " Destination: "); + //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[2] <<16 ) + (DmrDataByte[3] <<8 ) + DmrDataByte[4] ); + } + + if ( (state->data_header_format[state->currentslot] & 0x40) == 0x40 && state->data_p_head[state->currentslot] == 0) //check response req bit + { + fprintf (stderr, "\n Response Requested - "); fprintf (stderr, " Source:"); - fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); + fprintf (stderr, " [%d]", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); fprintf (stderr, " Destination:"); - fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + fprintf (stderr, " [%d]", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); + } + + //if proprietary header was flagged by the last data header, then process data differently + //maybe we could add the data header bytes found here into the 12 rate and/or 34 rate superframe + if (state->data_p_head[state->currentslot] == 1) + { + fprintf (stderr, "\n Proprietary Data Header: SAP %01X - Format %01X - MFID %02X", + (DmrDataByte[0] & 0xF0) >> 4, DmrDataByte[0] & 0xF, DmrDataByte[1] ); + + state->data_p_head[state->currentslot] = 0; + state->data_header_sap[state->currentslot] = 0; //reset this to zero so we don't trip the condition below + state->data_block_counter[state->currentslot]++; //increment the counter since this counts against the data blocks + //shim the databytes into the approprate 12 Rate Super Frame + uint8_t blocks = state->data_header_blocks[state->currentslot] - 1; + for(i = 0; i < 12; i++) + { + state->dmr_12_rate_sf[slot][i+(blocks*12)] = DmrDataByte[i]; + } + } + + //only set this flag after everything else is processed + if (state->data_header_sap[state->currentslot] == 0x9 && state->data_p_head[state->currentslot] == 0) //9 is Proprietary Packet data + { + fprintf (stderr, "\n Proprietary Packet Data Incoming "); + state->data_p_head[state->currentslot] = 1; //flag that next data header will be a proprietary data header } fprintf (stderr, "%s ", KNRM); + //Full if (opts->payload == 1) { @@ -484,11 +600,12 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint fprintf (stderr, "%s", KNRM); } + } void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -496,121 +613,102 @@ void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t uint32_t IrrecoverableErrors = 0; uint8_t DeInteleavedData[196]; uint8_t DmrDataBit[96]; - uint8_t DmrDataByte[12]; + uint8_t DmrDataByte[25]; TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL; uint8_t R[3]; uint8_t BPTCReservedBits = 0; + short int slot = 0; + slot = (short int)state->currentslot; - // Extract parameters for logging purposes - uint8_t csbk_lb = 0; - uint8_t csbk_pf = 0; - uint8_t csbk_o = 0; - uint8_t csbk_fid = 0; - uint64_t csbk_data = 0; - uint8_t csbk = 0; - - /* Check the current time slot */ - if(state->currentslot == 0) - { - TSVoiceSupFrame = &state->TS1SuperFrame; - } - else - { - TSVoiceSupFrame = &state->TS2SuperFrame; - } - - CRCExtracted = 0; - CRCComputed = 0; - IrrecoverableErrors = 0; - - /* Deinterleave DMR data */ - BPTCDeInterleaveDMRData(info, DeInteleavedData); - - /* Extract the BPTC 196,96 DMR data */ - IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); - - /* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */ - BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08); - - /* Convert the 96 bit of voice LC Header data into 12 bytes */ + //define our block and padding values + uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below + uint8_t padding = state->data_header_padding[slot]; + //shift data in the superframe up a block k = 0; - for(i = 0; i < 12; i++) + for(i = 0; i < 24; i++) { + //reuse dmr_12_rate_sf since 12, we can use 2 blocks to load 1 block here + state->dmr_12_rate_sf[slot][i] = state->dmr_12_rate_sf[slot][i+24]; //shift block 2 to block 1 + state->dmr_12_rate_sf[slot][i+24] = state->dmr_12_rate_sf[slot][i+48]; //shift block 3 to block 2 + state->dmr_12_rate_sf[slot][i+48] = state->dmr_12_rate_sf[slot][i+72]; //shift block 3 to block 2 DmrDataByte[i] = 0; for(j = 0; j < 8; j++) { DmrDataByte[i] = DmrDataByte[i] << 1; - DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); + DmrDataByte[i] = DmrDataByte[i] | (info[k] ); //& 1 k++; } + + //start loading new superframe at appropriate block count determined by the data header + state->dmr_12_rate_sf[slot][i+(blocks*24)] = DmrDataByte[i]; } + //need to rework this for rate 1 data, will be a crc 9 for each confirmed block, + //and/or CRC 32 on last block (full superframe) + //NOTE 2: Only used when CRC-9 present in burst. + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ - CRCExtracted = 0; - //for(i = 0; i < 24; i++) - 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 = 0; + // //for(i = 0; i < 24; i++) + // 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); + // } - //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; /* 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); - /* Convert corrected 12 bytes into 96 bits */ - for(i = 0, j = 0; i < 12; i++, j+=8) - { - DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; - DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; - DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; - DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; - DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; - DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; - DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; - DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; - } - // - if (DmrDataByte[0] == 0x43) - { - //fprintf (stderr, "\n IP4 Source IP:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination IP:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } - - if (DmrDataByte[0] == 0x01) - { - //fprintf (stderr, "\n LRRP Control ACK - "); - //fprintf (stderr, " Source:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } //Full if (opts->payload == 1) { fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull Rate 1 Payload "); - for (i = 0; i < 12; i++) + fprintf (stderr, "\nFull Rate 1 Payload \n"); + for (i = 0; i < 24; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); + if (i == 11) + { + fprintf (stderr, "\n"); + } + } + fprintf (stderr, "\n Hex to Ascii - "); + for (i = 0; i < 24; i++) + { + if (DmrDataByte[i] <= 0x7E && DmrDataByte[i] >=0x20) + { + fprintf (stderr, "%c", DmrDataByte[i]); + } + else fprintf (stderr, "."); } fprintf (stderr, "%s", KNRM); } + //Full Super Frame - Debug Output + if (opts->payload == 1 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n Rate 1 Superframe - Slot [%d]\n ",slot+1); + for (i = 0; i < ((blocks+1)*24); i++) //only print as many as we have blocks + { + fprintf (stderr, "[%02X]", state->dmr_12_rate_sf[slot][i]); + if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71) //line break and two spaces after each 12 bytes + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); + } + state->data_block_counter[state->currentslot]++; //increment block counter + } void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -623,14 +721,6 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint uint8_t R[3]; uint8_t BPTCReservedBits = 0; - // Extract parameters for logging purposes - uint8_t csbk_lb = 0; - uint8_t csbk_pf = 0; - uint8_t csbk_o = 0; - uint8_t csbk_fid = 0; - uint64_t csbk_data = 0; - uint8_t csbk = 0; - /* Check the current time slot */ if(state->currentslot == 0) { @@ -669,22 +759,16 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ CRCExtracted = 0; - //for(i = 0; i < 24; i++) 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 + 80] & 1); } - //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 ^ 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, 0xAAAA); /* Convert corrected 12 bytes into 96 bits */ @@ -699,23 +783,7 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; } - // - if (DmrDataByte[0] == 0x43) - { - //fprintf (stderr, "\n IP4 Source IP:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination IP:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } - if (DmrDataByte[0] == 0x01) - { - //fprintf (stderr, "\n LRRP Control ACK - "); - //fprintf (stderr, " Source:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } //Full if (opts->payload == 1) { @@ -732,7 +800,7 @@ void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -745,14 +813,6 @@ void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 uint8_t R[3]; uint8_t BPTCReservedBits = 0; - // Extract parameters for logging purposes - uint8_t csbk_lb = 0; - uint8_t csbk_pf = 0; - uint8_t csbk_o = 0; - uint8_t csbk_fid = 0; - uint64_t csbk_data = 0; - uint8_t csbk = 0; - /* Check the current time slot */ if(state->currentslot == 0) { @@ -789,25 +849,24 @@ void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 } } - /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ - CRCExtracted = 0; - //for(i = 0; i < 24; i++) - 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 - } + //NO CRC or FEC on MBC Cont. Data? + //...that seems to be according to the manual - //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 + /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ + // CRCExtracted = 0; + // for(i = 0; i < 16; i++) + // { + // CRCExtracted = CRCExtracted << 1; + // CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); + // } + + //No CRC Mask for MBC Continuation Data + //Note 1. None required for intermediate or last blocks. /* 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; /* 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, 0x0); //0, or FFFF? /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -821,28 +880,12 @@ void ProcessMBCData(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; } - // - if (DmrDataByte[0] == 0x43) - { - //fprintf (stderr, "\n IP4 Source IP:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination IP:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } - if (DmrDataByte[0] == 0x01) - { - //fprintf (stderr, "\n LRRP Control ACK - "); - //fprintf (stderr, " Source:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } //Full if (opts->payload == 1) { fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull MBC Payload "); + fprintf (stderr, "\nFull MBC Continuation Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); @@ -852,9 +895,10 @@ void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 } -void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +//This data shouldn't be active, but come here to dump in case of data burst type decoding failure +void ProcessReservedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -867,13 +911,74 @@ void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 uint8_t R[3]; uint8_t BPTCReservedBits = 0; - // Extract parameters for logging purposes - uint8_t csbk_lb = 0; - uint8_t csbk_pf = 0; - uint8_t csbk_o = 0; - uint8_t csbk_fid = 0; - uint64_t csbk_data = 0; - uint8_t csbk = 0; + /* Check the current time slot */ + if(state->currentslot == 0) + { + TSVoiceSupFrame = &state->TS1SuperFrame; + } + else + { + TSVoiceSupFrame = &state->TS2SuperFrame; + } + + /* Convert the 196 bit of voice LC Header data into 12 bytes */ + k = 0; + for(i = 0; i < 24; i++) + { + DmrDataByte[i] = 0; + for(j = 0; j < 8; j++) + { + DmrDataByte[i] = DmrDataByte[i] << 1; + DmrDataByte[i] = DmrDataByte[i] | info[i]; + k++; + } + } + + /* Convert corrected 12 bytes into 96 bits */ + for(i = 0, j = 0; i < 12; i++, j+=8) + { + DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01; + DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01; + DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01; + DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01; + DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01; + DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01; + DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01; + DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01; + } + + //Full + if (opts->payload == 1) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, "\nFull Reserved Payload "); + for (i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", DmrDataByte[i]); + } + fprintf (stderr, "%s", KRED); + fprintf (stderr, "\nINFO! This Payload Dump May be caused by erroneous data burst type decoding! "); + fprintf (stderr, "%s", KNRM); + } + +} + +void ProcessUnifiedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) +{ + + uint32_t i, j, k; + uint32_t CRCExtracted = 0; + uint32_t CRCComputed = 0; + uint32_t CRCCorrect = 0; + uint32_t IrrecoverableErrors = 0; + uint8_t DeInteleavedData[196]; + uint8_t DmrDataBit[96]; + uint8_t DmrDataByte[12]; + 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) @@ -898,7 +1003,7 @@ void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 /* 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); - /* Convert the 96 bit of voice LC Header data into 12 bytes */ + k = 0; for(i = 0; i < 12; i++) { @@ -909,6 +1014,7 @@ void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); k++; } + } /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ @@ -917,19 +1023,30 @@ void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 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 + 80] & 1); } - //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 ^ 0x3333; /* 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, 0x3333); + + //test + if((IrrecoverableErrors == 0) && CRCCorrect) + { + //fprintf (stderr, "\n(Unified Data CRC Okay)"); + } + else if((IrrecoverableErrors == 0)) + { + //fprintf (stderr, "\n(Unified Data FEC Okay)"); + } + else + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, ("\n(Unified Rate CRC Fail, FEC Fail)")); + fprintf (stderr, "%s", KNRM); + } /* Convert corrected 12 bytes into 96 bits */ for(i = 0, j = 0; i < 12; i++, j+=8) @@ -943,38 +1060,30 @@ void ProcessWTFData(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; } - // - if (DmrDataByte[0] == 0x43) - { - //fprintf (stderr, "\n IP4 Source IP:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination IP:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } - if (DmrDataByte[0] == 0x01) - { - //fprintf (stderr, "\n LRRP Control ACK - "); - //fprintf (stderr, " Source:"); - //fprintf (stderr, " %d", (DmrDataByte[2] <<16 ) + (DmrDataByte[3] << 8) + DmrDataByte[4] ); - //fprintf (stderr, " Destination:"); - //fprintf (stderr, " %d", (DmrDataByte[5] <<16 ) + (DmrDataByte[6] <<8 ) + DmrDataByte[7] ); - } //Full if (opts->payload == 1) { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "\nFull WTF Payload "); + fprintf (stderr,"%s", KCYN); + fprintf (stderr, "\n Full Unified Data Payload "); for (i = 0; i < 12; i++) { fprintf (stderr, "[%02X]", DmrDataByte[i]); } - fprintf (stderr, "%s", KNRM); + 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); } } - void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { @@ -1015,14 +1124,19 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ /* 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); - /* Convert the 96 bit of voice LC Header data into 12 bytes */ + //define our block and padding values + uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below + uint8_t padding = state->data_header_padding[slot]; + //shift data in the superframe up a block k = 0; for(i = 0; i < 12; i++) { - 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]; + state->dmr_12_rate_sf[slot][i] = state->dmr_12_rate_sf[slot][i+12]; //shift block 2 to block 1 + state->dmr_12_rate_sf[slot][i+12] = state->dmr_12_rate_sf[slot][i+24]; //shift block 3 to block 2 + state->dmr_12_rate_sf[slot][i+24] = state->dmr_12_rate_sf[slot][i+36]; //shift block 4 to block 3 + state->dmr_12_rate_sf[slot][i+36] = state->dmr_12_rate_sf[slot][i+48]; //shift block 5 to block 4 + state->dmr_12_rate_sf[slot][i+48] = state->dmr_12_rate_sf[slot][i+60]; //shift block 6 to block 5 + state->dmr_12_rate_sf[slot][i+60] = state->dmr_12_rate_sf[slot][i+72]; //shift block 7 to block 6 DmrDataByte[i] = 0; for(j = 0; j < 8; j++) { @@ -1030,43 +1144,24 @@ 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[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); + //start loading new superframe at appropriate block count determined by the data header + state->dmr_12_rate_sf[slot][i+(blocks*12)] = DmrDataByte[i]; //if 3 blocks, then start at position 36; 4 blocks at 48, 5 at } /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ CRCExtracted = 0; - //for(i = 0; i < 24; i++) - for(i = 0; i < 16; i++) + for(i = 0; i < 24; 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 } - //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; /* 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); //test if((IrrecoverableErrors == 0) && CRCCorrect) @@ -1096,111 +1191,63 @@ 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 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, "%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[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]); - } - } - 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[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) ); - 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[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); - } - } - } - //end Jurek lrrp - */ + //Start Polling the 1/2 Rate Super Frame for Data when byte 0 contains values //LRRP + int message_legnth = 0; 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 + + //find user home directory and append directory and filename. + FILE * pFile; //put this outside of the if statement? + if (opts->lrrp_file_output == 1) { - /* + char * filename = "/lrrp.txt"; + char * home_dir = getenv("HOME"); + char * filepath = malloc(strlen(home_dir) + strlen(filename) + 1); + strncpy (filepath, home_dir, strlen(home_dir) + 1); + strncat (filepath, filename, strlen(filename) + 1); + //end find user home directory and append directory and filename + + pFile = fopen (filepath, "a"); + + //hard code filename override for those wanting to use other software + //pFile = fopen("DSDPlus.LRRP", "a"); + + + fprintf (pFile, "%s\t %s\t", getDateL(), getTimeL()); //current timestamp, may find a way to only add this IF no included timestamp in LRRP data? + fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header + } + + + fprintf (stderr, "%s ", KMAG); + + //go to number of octets minus padding and crc, confirmed data may need a second rule to skip Serial Numbers and Block CRCs + for (short i = 12; i < ( ((blocks+1)*12) - (padding+4) ); i++) + { + if ( state->dmr_12_rate_sf[slot][i] == 0x0C) //Source and Destination info { - fprintf (stderr, "\n Source:"); + 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, " - 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]); + + i = i + 12; //skip 12 bytes here so we don't accidentally trip another flag with data in these bytes } - */ - if ( state->dmr_12_rate_sf[slot][i] == 0x34 ) //timestamp + + if (state->dmr_12_rate_sf[slot][i] == 0x0D) //This should lock on to the second 0x0D value hopefully and tell us the message legnth + { + message_legnth = state->dmr_12_rate_sf[slot][i+1]; + fprintf (stderr, "\n Message Legnth: %02d", message_legnth); + i = i + 2; //skip 2 bytes here so we don't accidentally trip another flag with data in these bytes + } + + if ( state->dmr_12_rate_sf[slot][i] == 0x34 && message_legnth > 27 ) //timestamp, seems to need legnth of 28 { 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 @@ -1208,15 +1255,22 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ 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 + fprintf (stderr, "%02d", ( (state->dmr_12_rate_sf[slot][i+5] & 0x3F) << 0) ); //2 digit second + + i = i + 6; //skip 6 bytes here so we don't accidentally trip another flag with data in these bytes } - if ( state->dmr_12_rate_sf[slot][i] == 0x51 ) //lattitude and longitude + + if ( state->dmr_12_rate_sf[slot][i] == 0x51 && message_legnth > 13) //lattitude and longitude, message_lenght > 13? { 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, "-"); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "-"); + } } long int lrrplat; long int lrrplon; @@ -1225,12 +1279,20 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ 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); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.5lf\t", ((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 (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.5lf\t", (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) ); @@ -1242,24 +1304,47 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ fprintf (stderr, " (-%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); } else fprintf (stderr, " (%.5lf, %.5lf)", ((double)lrrplat) * lat_unit , (lrrplon * lon_unit) ); + + i = i + 9 + 2; //skip 9 bytes here so we don't accidentally trip another flag with data in these bytes } - if ( state->dmr_12_rate_sf[slot][i] == 0x6C ) + if ( state->dmr_12_rate_sf[slot][i] == 0x6C && message_legnth > 13) { - //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. + //either Plus is wrong, or I'm wrong on higher velocities exceeding 0xFF. double check double values? //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) ); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%.3lf\t ", (velocity * 3.6) ); + } + fprintf (stderr, "\n LRRP - Velocity: %.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)); + + i = i + 3; //skip 3 bytes here so we don't accidentally trip another flag with data in these bytes } - if ( state->dmr_12_rate_sf[slot][i] == 0x56 ) + if ( state->dmr_12_rate_sf[slot][i] == 0x56 && message_legnth > 13) { //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); + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "%d\t", state->dmr_12_rate_sf[slot][i+1] * 2); + } + fprintf (stderr, "\n LRRP - Track: %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); + + i = ((blocks+1)*12); //skip to end of loop here so we don't accidentally trip another flag with data in these bytes } + //try for a Control ACK at the very end if nothing else pops, flag still unknown + if ( (state->dmr_12_rate_sf[slot][i] == 0x36 || state->dmr_12_rate_sf[slot][i] == 0x37) && message_legnth > 6 ) + { + fprintf (stderr, "\n LRRP - Control ACK "); + } + } + if (opts->lrrp_file_output == 1) + { + fprintf (pFile, "\n"); + fclose (pFile); } } fprintf (stderr, "%s ", KNRM); @@ -1284,12 +1369,28 @@ void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_ } fprintf (stderr,"%s", KNRM); } + //Full Super Frame - Debug Output + if (opts->payload == 1 && state->data_block_counter[state->currentslot] == state->data_header_blocks[state->currentslot]) + { + fprintf (stderr, "%s",KGRN); + fprintf (stderr, "\n Rate 1/2 Superframe - Slot [%d]\n ",slot+1); + for (i = 0; i < ((blocks+1)*12); i++) //only print as many as we have blocks + { + fprintf (stderr, "[%02X]", state->dmr_12_rate_sf[slot][i]); + if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71) //line break and two spaces after each 12 bytes + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); + } + state->data_block_counter[state->currentslot]++; //increment block counter } void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -1356,14 +1457,10 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t 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 ^ 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, 0xA5A5); //test @@ -1589,7 +1686,7 @@ void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]) { - //Placeholder + uint32_t i, j, k; uint32_t CRCExtracted = 0; uint32_t CRCComputed = 0; @@ -1602,11 +1699,6 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u uint8_t R[3]; uint8_t BPTCReservedBits = 0; - /* Remove warning compiler */ - //UNUSED_VARIABLE(syncdata[0]); - //UNUSED_VARIABLE(SlotType[0]); - //UNUSED_VARIABLE(BPTCReservedBits); - /* Check the current time slot */ if(state->currentslot == 0) { @@ -1653,14 +1745,10 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u 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; /* 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); /* Convert corrected 12 bytes into 96 bits */ @@ -1681,6 +1769,7 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u state->payload_algid = DmrDataByte[0]; state->payload_keyid = DmrDataByte[2]; state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); + //state->payload_mi = 0; //testing for late entry, remove later if (state->payload_algid < 0x26) //have it always print? only if a good value, was 1 == 1 { fprintf (stderr, "%s ", KYEL); @@ -1701,6 +1790,7 @@ void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], u state->payload_algidR = DmrDataByte[0]; state->payload_keyidR = DmrDataByte[2]; state->payload_miR = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) ); + //state->payload_miR = 0; //testing for late entry, remove later if (state->payload_algidR < 0x26) //have it always print? only if a good value, was 1 == 1 { fprintf (stderr, "%s ", KYEL); @@ -1760,11 +1850,6 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 uint8_t R[3]; uint8_t BPTCReservedBits = 0; - /* Remove warning compiler */ - //UNUSED_VARIABLE(syncdata[0]); - //UNUSED_VARIABLE(SlotType[0]); - //UNUSED_VARIABLE(BPTCReservedBits); - /* Check the current time slot */ if(state->currentslot == 0) { @@ -1846,7 +1931,7 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 /* Store the Group address (Talk Group) */ TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24); - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + /* Store the Source address */ TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24); //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; @@ -1855,6 +1940,27 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 { /* CRC is correct so consider the Full LC data as correct/valid */ TSVoiceSupFrame->FullLC.DataValidity = 1; + if (state->currentslot == 0) + { + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } + } + else if(IrrecoverableErrors == 0) + { + //FEC okay? Set SVCop code anyways + TSVoiceSupFrame->FullLC.DataValidity = 0; //shouldn't matter in this context + if (state->currentslot == 0) + { + state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + } + if (state->currentslot == 1) + { + state->dmr_soR = TSVoiceSupFrame->FullLC.ServiceOptions; + } } else { @@ -1871,30 +1977,19 @@ 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 TGT=%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->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - - //HERE HERE do some work to get this Emergency and BP modes to display in ncurses - //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + fprintf (stderr, "%s \n", KGRN); + fprintf (stderr, " Slot %d ", state->currentslot+1); + fprintf(stderr, " TGT=%u SRC=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x80) fprintf(stderr, "Emergency "); if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x40) { - /* By default select the basic privacy (BP), if the encryption mode is EP ARC4 or AES256 - * 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); @@ -1984,12 +2079,6 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 uint8_t R[3]; uint8_t BPTCReservedBits = 0; - /* Remove warning compiler */ - //UNUSED_VARIABLE(opts); - //UNUSED_VARIABLE(syncdata[0]); - //UNUSED_VARIABLE(SlotType[0]); - //UNUSED_VARIABLE(BPTCReservedBits); - /* Check the current time slot */ if(state->currentslot == 0) { @@ -2071,12 +2160,10 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 /* Store the Group address (Talk Group) */ TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24); - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + /* Store the Source address */ TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24); - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - //TSVoiceSupFrame->FullLC.LeftOvers = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[64], 8); - //fprintf (stderr, "\nBPTC Left Overs = %02X \n", TSVoiceSupFrame->FullLC.LeftOvers); + if((IrrecoverableErrors == 0))// && CRCCorrect) { /* CRC is correct so consider the Full LC data as correct/valid */ @@ -2088,30 +2175,24 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 TSVoiceSupFrame->FullLC.DataValidity = 0; } - /* Print the destination ID (TG) and the source ID */ - //fprintf(stderr, "\n TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress); - //fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID); - - //reset alg, keys, mi during a TLC call termination EVENT so we aren't stuck on an old value, PI header will proceed a new call if BP isn't used - //assuming the TLC frame comes on the same slot as the call it was terminating? not sure? + //reset alg, keys, mi during a TLC call termination EVENT so we aren't stuck on an old value if (state->currentslot == 0) { - //state->payload_algid = 0; //try disablign all of these? - //state->payload_keyid = 0; + state->payload_algid = 0; + state->payload_keyid = 0; //state->payload_mfid = 0; - //state->payload_mi = 0; //let's try disabling this for a bit + state->payload_mi = 0; } if (state->currentslot == 1) { - //state->payload_algidR = 0; //try disablign all of these? - //state->payload_keyidR = 0; + state->payload_algidR = 0; + state->payload_keyidR = 0; //state->payload_mfid = 0; - //state->payload_miR = 0; ////let's try disabling this for a bit + state->payload_miR = 0; } - //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 { @@ -2122,39 +2203,18 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 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 || - 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 (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; - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - //state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - //state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; - //state->dmr_color_code = state->color_code; } else if(IrrecoverableErrors == 0) { @@ -2165,37 +2225,19 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 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 || - 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 (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; - //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; - //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)"); @@ -2319,7 +2361,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) CRCExtracted |= (LC_DataBit[74] & 1) << 2; CRCExtracted |= (LC_DataBit[75] & 1) << 1; CRCExtracted |= (LC_DataBit[76] & 1) << 0; - //fprintf (stderr, "\nLCDB = 0x%X \n", LC_DataBit); + /* Compute the 5 bit CRC */ CRCComputed = ComputeCrc5Bit(LC_DataBit); @@ -2344,7 +2386,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) /* Store the Group address (Talk Group) */ TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[24], 24); - //state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress; + /* Store the Source address */ TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[48], 24); //state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; @@ -2456,22 +2498,11 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) 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_color_code = state->color_code; } else if(IrrecoverableErrors == 0) { - //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)"); //voice burst - //or set if was corrected + if (TSVoiceSupFrame->FullLC.FullLinkControlOpcode < 0x04 || TSVoiceSupFrame->FullLC.FullLinkControlOpcode > 0x08) //7, or 8? { fprintf (stderr, "%s", KGRN); @@ -2491,7 +2522,7 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress; //state->dmr_color_code = state->color_code; state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID; - state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; + // state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions; } if (state->currentslot == 1) { @@ -2499,17 +2530,9 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) 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_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_color_code = state->color_code; } else {} //fprintf(stderr, "\n(FEC FAIL/CRC ERR)"); @@ -2552,6 +2575,8 @@ void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state) { 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, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed); fprintf (stderr, "%s", KNRM); diff --git a/src/dmr_voice.c b/src/dmr_voice.c index 3e5170a..db0fd24 100644 --- a/src/dmr_voice.c +++ b/src/dmr_voice.c @@ -646,8 +646,8 @@ void processDMRvoice (dsd_opts * opts, dsd_state * state) ProcessDMR(opts, state); //LFSR if required, change condition? - if ( (state->currentslot == 0 && state->payload_algid != 0 ) || //&& opts->payload == 1 - (state->currentslot == 1 && state->payload_algidR != 0 ) ) //&& opts->payload == 1 + if ( (state->currentslot == 0 && state->payload_algid == 0x21 ) || //&& opts->payload == 1 + (state->currentslot == 1 && state->payload_algidR == 0x21 ) ) //&& opts->payload == 1 { LFSR(state); } diff --git a/src/dsd_audio.c b/src/dsd_audio.c index fc0c08b..73df689 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -22,6 +22,20 @@ pa_sample_spec tt; pa_sample_spec zz; pa_sample_spec cc; +void closePulseOutput (dsd_opts * opts) +{ + pa_simple_free (opts->pulse_digi_dev_out); + if (opts->dmr_stereo == 1) + { + pa_simple_free (opts->pulse_digi_dev_outR); + } +} + +void closePulseInput (dsd_opts * opts) +{ + pa_simple_free (opts->pulse_digi_dev_in); +} + void openPulseOutput(dsd_opts * opts) { @@ -35,7 +49,7 @@ void openPulseOutput(dsd_opts * opts) if (opts->monitor_input_audio == 1) { - opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); + opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); } //tt @@ -47,10 +61,11 @@ void openPulseOutput(dsd_opts * opts) 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-FME1", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO SLOT 1", &tt, left, NULL, NULL); - opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME2", PA_STREAM_PLAYBACK, NULL, "DMR/MOTOTRBO SLOT 2", &tt, right, NULL, NULL); + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME1", PA_STREAM_PLAYBACK, NULL, "DMR SLOT 1", &tt, left, NULL, NULL); + opts->pulse_digi_dev_outR = pa_simple_new(NULL, "DSD-FME2", PA_STREAM_PLAYBACK, NULL, "DMR SLOT 2", &tt, right, NULL, NULL); } } @@ -348,8 +363,7 @@ processAudioR (dsd_opts * opts, dsd_state * state) } } -void -writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) +void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) { int n; short aout_buf[160]; @@ -377,6 +391,50 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) } +void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) +{ + int n; + short aout_buf[160]; + short *aout_buf_p; + + aout_buf_p = aout_buf; + state->audio_out_temp_buf_pR = state->audio_out_temp_bufR; + + for (n = 0; n < 160; n++) + { + if (*state->audio_out_temp_buf_pR > (float) 32767) + { + *state->audio_out_temp_buf_pR = (float) 32767; + } + else if (*state->audio_out_temp_buf_pR < (float) -32768) + { + *state->audio_out_temp_buf_pR = (float) -32768; + } + *aout_buf_p = (short) *state->audio_out_temp_buf_pR; + aout_buf_p++; + state->audio_out_temp_buf_pR++; + } + + sf_write_short(opts->wav_out_fR, aout_buf, 160); + +} + +void writeRawSample (dsd_opts * opts, dsd_state * state, short sample) +{ + int n; + short aout_buf[160]; + short *aout_buf_p; + + //sf_write_short(opts->wav_out_raw, aout_buf, 160); + + //only write if actual audio, truncate silence + if (sample != 0) + { + sf_write_short(opts->wav_out_raw, &sample, 2); //2 to match pulseaudio input sample read + } + +} + void playSynthesizedVoice (dsd_opts * opts, dsd_state * state) { @@ -396,22 +454,6 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) state->audio_out_idx = 0; } - //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. - state->audio_out_idx = 0; - } - - //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; - } - */ - } @@ -443,14 +485,6 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) 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; - } - */ } @@ -467,17 +501,13 @@ playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state) void openAudioOutDevice (dsd_opts * opts, int speed) { + //converted to handle any calls to use portaudio if(strncmp(opts->audio_out_dev, "pa:", 3) == 0) { - opts->audio_out_type = 2; -#ifdef USE_PORTAUDIO - int err = getPADevice(opts->audio_out_dev, 0, &opts->audio_out_pa_stream); - if(err != 0) - exit(err); -#else - fprintf (stderr,"Error, Portaudio support not compiled.\n"); - exit(1); -#endif + opts->audio_out_type = 0; + fprintf (stderr,"Error, Port Audio is not supported by FME!\n"); + fprintf (stderr,"Using Pulse Audio Output Stream Instead! \n"); + sprintf (opts->audio_out_dev, "pulse"); } if(strncmp(opts->audio_in_dev, "pulse", 5) == 0) { @@ -522,25 +552,13 @@ openAudioInDevice (dsd_opts * opts) exit(1); //had this one disabled, re-enabling it now } } + //converted to handle any calls to use portaudio else if(strncmp(opts->audio_in_dev, "pa:", 2) == 0) { - opts->audio_in_type = 2; -#ifdef USE_PORTAUDIO - int err = getPADevice(opts->audio_in_dev, 1, &opts->audio_in_pa_stream); - if(err != 0) - exit(err); - - if (opts->split == 0) - { - int err = getPADevice(opts->audio_in_dev, 0, &opts->audio_out_pa_stream); - if(err != 0) - exit(err); - } - -#else - fprintf (stderr,"Error, Portaudio support not compiled.\n"); - exit(1); -#endif + opts->audio_in_type = 0; + fprintf (stderr,"Error, Port Audio is not supported by FME!\n"); + fprintf (stderr,"Using Pulse Audio Input Stream Instead! \n"); + sprintf (opts->audio_in_dev, "pulse"); } else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0) { @@ -550,28 +568,32 @@ openAudioInDevice (dsd_opts * opts) { opts->audio_in_type = 0; } + //convert from opening wav files to OP25 symbol capture files since opening wav files is busted else { - struct stat stat_buf; - if (stat(opts->audio_in_dev, &stat_buf) != 0) + struct stat stat_buf; + if (stat(opts->audio_in_dev, &stat_buf) != 0) { fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); exit(1); } - if (S_ISREG(stat_buf.st_mode)) + if (S_ISREG(stat_buf.st_mode)) { // is this a regular file? then process with libsndfile. //opts->pulse_digi_rate_out = 8000; //this for wav files input? - opts->audio_in_type = 1; - opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); - opts->audio_in_file_info->channels = 1; - opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); + // opts->audio_in_type = 1; + // opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); + // opts->audio_in_file_info->channels = 1; + // opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); + // + // if(opts->audio_in_file == NULL) + // { + // fprintf (stderr,"Error, couldn't open file %s\n", opts->audio_in_dev); + // exit(1); + // } - if(opts->audio_in_file == NULL) - { - fprintf (stderr,"Error, couldn't open file %s\n", opts->audio_in_dev); - exit(1); - } + opts->symbolfile = fopen(opts->audio_in_dev, "r"); + opts->audio_in_type = 4; //symbol capture bin files } else { diff --git a/src/dsd_dibit.c b/src/dsd_dibit.c index 1ef3820..bd4b261 100644 --- a/src/dsd_dibit.c +++ b/src/dsd_dibit.c @@ -376,6 +376,7 @@ static int digitize (dsd_opts* opts, dsd_state* state, int symbol) *state->dmr_payload_p = dibit; state->dmr_payload_p++; //dmr buffer end + return dibit; } } @@ -386,6 +387,19 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s int symbol; int dibit; + // if (opts->audio_in_type == 4 && opts->frame_provoice == 1) // + // { + // //skip processing symbol as dibit and use it as is + // if (state->symbolc == 0) + // { + // symbol = 1; + // } + // if (state->symbolc == 1) + // { + // symbol = 3; + // } + // } + #ifdef TRACE_DSD unsigned int l, r; #endif @@ -402,7 +416,7 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s r = state->debug_sample_index; #endif - // + state->sbuf[state->sidx] = symbol; if (out_analog_signal != NULL) @@ -414,6 +428,21 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s dibit = digitize (opts, state, symbol); + //don't think this is quite right still, but should work, don't know why it doesn't + if (opts->audio_in_type == 4 && opts->frame_provoice == 1) // + { + //skip processing symbol as dibit and use it as is + dibit = state->symbolc; + } + + //symbol/dibit file capture/writing + //need this bit here to capture dibits once sync starts + if (opts->symbol_out == 1) + { + //fprintf (stderr, "%d", dibit); + fputc (dibit, opts->symbol_out_f); + } + #ifdef TRACE_DSD { float left, right; diff --git a/src/dsd_file.c b/src/dsd_file.c index 104b033..e15d24c 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -179,9 +179,9 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere } else fprintf(stderr, " err = [%X] [%X] ", state->errsR, state->errs2R); b = ambe_d[48]; - if (opts->dmr_stereo == 1) + if (opts->dmr_stereo == 1) //need to fix the printouts again { - fprintf (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -460,74 +460,113 @@ openWavOutFile (dsd_opts * opts, dsd_state * state) // state->wav_out_bytes = 0; } +void openWavOutFileL (dsd_opts * opts, dsd_state * state) +{ -void -closeWavOutFile (dsd_opts * opts, dsd_state * state) + SF_INFO info; + info.samplerate = 8000; //8000 + info.channels = 1; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; + //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); + opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file + + if (opts->wav_out_f == NULL) + { + fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file); + return; + } + +// state->wav_out_bytes = 0; + +} + +void openWavOutFileR (dsd_opts * opts, dsd_state * state) +{ + + SF_INFO info; + info.samplerate = 8000; //8000 + info.channels = 1; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; + //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); + opts->wav_out_fR = sf_open (opts->wav_out_fileR, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file + + if (opts->wav_out_f == NULL) + { + fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_fileR); + return; + } + +// state->wav_out_bytes = 0; + +} + +void openWavOutFileRaw (dsd_opts * opts, dsd_state * state) +{ + + SF_INFO info; + info.samplerate = 48000; //8000 + info.channels = 1; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; + //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info); + //opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file + opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info); + if (opts->wav_out_raw == NULL) + { + fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw); + return; + } + +// state->wav_out_bytes = 0; + +} + +void closeWavOutFile (dsd_opts * opts, dsd_state * state) { sf_close(opts->wav_out_f); - -/* - int length; - - if (opts->wav_out_f != NULL) - { - rewind (opts->wav_out_f); - length = state->wav_out_bytes; - - fprintf (stderr,opts->wav_out_f, "RIFF"); - // total length - fputc (((36 + length) & 0xff), opts->≈≈); - fputc ((((36 + length) >> 8) & 0xff), opts->wav_out_f); - fputc ((((36 + length) >> 16) & 0xff), opts->wav_out_f); - fputc ((((36 + length) >> 24) & 0xff), opts->wav_out_f); - - fprintf (stderr,opts->wav_out_f, "WAVE"); - fprintf (stderr,opts->wav_out_f, "fmt "); - - // length of format chunk - fputc (16, opts->wav_out_f); - fputc (0, opts->wav_out_f); - fputc (0, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // always 0x1 - fputc (1, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // channels - fputc (1, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // sample rate - fputc (64, opts->wav_out_f); - fputc (31, opts->wav_out_f); - fputc (0, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // bytes per second - fputc (128, opts->wav_out_f); - fputc (62, opts->wav_out_f); - fputc (0, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // block align - fputc (2, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // bits/sample - fputc (16, opts->wav_out_f); - fputc (0, opts->wav_out_f); - - // data chunk header - fprintf (stderr,opts->wav_out_f, "data"); - - // length of data - fputc ((length & 0xff), opts->wav_out_f); - fputc (((length >> 8) & 0xff), opts->wav_out_f); - fputc (((length >> 16) & 0xff), opts->wav_out_f); - fputc (((length >> 24) & 0xff), opts->wav_out_f); - - fflush (opts->wav_out_f); - } - */ +} + +void closeWavOutFileL (dsd_opts * opts, dsd_state * state) +{ + sf_close(opts->wav_out_f); +} + +void closeWavOutFileR (dsd_opts * opts, dsd_state * state) +{ + sf_close(opts->wav_out_fR); +} + +void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state) +{ + sf_close(opts->wav_out_raw); +} + +void openSymbolOutFile (dsd_opts * opts, dsd_state * state) +{ + //Do something + opts->symbol_out_f = fopen (opts->symbol_out_file, "w"); +} + +void writeSymbolOutFile (dsd_opts * opts, dsd_state * state) +{ + //Do something + +} + +void closeSymbolOutFile (dsd_opts * opts, dsd_state * state) +{ + //Do something + if (opts->symbol_out == 1) + { + if (opts->symbol_out_file != NULL) //check first, or issuing a second fclose will crash the SOFTWARE + { + fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once + //noCarrier(opts, state); //free(): double free detected in tcache 2 (this is a new one) + } + + opts->symbol_out = 0; //set flag to 1 + //sprintf (opts->symbol_out_file, "fme-capture.bin"); //use fme for the symbol bin ext + //openSymbolOutFile (opts, state); + + } + } diff --git a/src/dsd_frame.c b/src/dsd_frame.c index d48dd63..b5c910c 100644 --- a/src/dsd_frame.c +++ b/src/dsd_frame.c @@ -105,6 +105,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } sprintf (state->fsubtype, " VOICE "); processNXDNVoice (opts, state); + //ProcessNXDNFrame (opts, state, 0); return; } else if ((state->synctype == 16) || (state->synctype == 17)) //NXDN Data @@ -128,6 +129,7 @@ processFrame (dsd_opts * opts, dsd_state * state) } sprintf (state->fsubtype, " DATA "); processNXDNData (opts, state); + //ProcessNXDNFrame (opts, state, 0); return; } else if ((state->synctype == 6) || (state->synctype == 7)) @@ -233,6 +235,7 @@ processFrame (dsd_opts * opts, dsd_state * state) if (opts->dmr_stereo == 1) { dmrMSData (opts, state); + } } else @@ -243,6 +246,7 @@ processFrame (dsd_opts * opts, dsd_state * state) state->err_str[0] = 0; sprintf (state->slot1light, " slot1 "); sprintf (state->slot2light, " slot2 "); + state->payload_miP = 0; //zero out when switching back to data sync processDMRdata (opts, state); } //switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata @@ -251,6 +255,7 @@ processFrame (dsd_opts * opts, dsd_state * state) state->dmr_stereo = 0; //set the state to zero for handling pure data frames sprintf (state->slot1light, " slot1 "); sprintf (state->slot2light, " slot2 "); + state->payload_miP = 0; //zero out when switching back to data sync processDMRdata (opts, state); } } @@ -314,6 +319,19 @@ processFrame (dsd_opts * opts, dsd_state * state) processYSF(opts, state); return; } + //P25 P2 + else if ((state->synctype == 35) || (state->synctype == 36)) + { + //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 "); + processP2(opts, state); + return; + } //dPMR else if ((state->synctype == 20) || (state->synctype == 24)) { @@ -481,6 +499,12 @@ processFrame (dsd_opts * opts, dsd_state * state) state->lastp25type = 1; sprintf (state->fsubtype, " LDU1 "); state->numtdulc = 0; + if (state->payload_algid == 0x81) + { + fprintf (stderr, "\n"); + //LFSRP (state); //HERE HERE best placement? + } + processLDU1 (opts, state); } else if (strcmp (duid, "22") == 0) diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index c8fceb8..1d018dc 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -144,12 +144,15 @@ getFrameSync (dsd_opts * opts, dsd_state * state) * 32 = DMR MS Voice * 33 = DMR MS Data * 34 = DMR RC Data + * 35 = +P25 P2 + * 36 = -P25 P2 */ int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt; char synctest[25]; char synctest12[13]; //dPMR + char synctest10[11]; char synctest18[19]; char synctest32[33]; char synctest20[21]; //YSF @@ -269,6 +272,22 @@ getFrameSync (dsd_opts * opts, dsd_state * state) dibit = 51; // '3' } + //this is needed to capture dibits and convert them to appropriate format for a symbol bin + if (opts->symbol_out == 1 && symbol != 0) //is 0 a valid symbol from dsd? //&& symbol != 0 + { + int csymbol = 0; + if (dibit == 49) + { + csymbol = 1; //1 + } + if (dibit == 51) + { + csymbol = 3; //3 + } + //fprintf (stderr, "%d", dibit); + fputc (csymbol, opts->symbol_out_f); + } + //digitize test for storing dibits in buffer correctly for dmr recovery if (state->dmr_payload_p > state->dmr_payload_buf + 900000) @@ -597,6 +616,52 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } } //end YSF sync + //P25 P2 sync + strncpy(synctest20, (synctest_p - 19), 20); //double check make sure this is right + if(opts->frame_p25p2 == 1) //(opts->frame_ysf == 1 + { + if (0 == 0) //opts->inverted_ysf == 0 + { + if (strcmp(synctest20, P25P2_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + fprintf (stderr, "\n+P25-P2 Sync"); + 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 (35); + } + } + } + if(opts->frame_p25p2 == 1) //(opts->frame_p25p2 == 1 + { + if (0 == 0) //inverted p25 + { + if (strcmp(synctest20, INV_P25P2_SYNC) == 0) + { + state->carrier = 1; + state->offset = synctest_pos; + state->max = ((state->max) + lmax) / 2; + state->min = ((state->min) + lmin) / 2; + fprintf (stderr, "\n-P25-P2 Sync"); + 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 (36); + } + } + } //dPMR sync strncpy(synctest, (synctest_p - 23), 24); strncpy(synctest12, (synctest_p - 11), 12); @@ -1093,6 +1158,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } } + if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1)) { strncpy (synctest18, (synctest_p - 17), 18); diff --git a/src/dsd_main.c b/src/dsd_main.c index 0498309..164db32 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -43,20 +43,19 @@ int pretty_colors() #include "p25p1_heuristics.h" #include "pa_devs.h" -short int butt = 1; +short int butt = 0; char * FM_banner[9] = { - " 2022 Dove Award Winner CTRL + C twice to exit", + " ", " ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗", " ██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝", " ██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ ", " ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ", " ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗", " ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝", - "https://github.com/lwvmobile/dsd-fme/tree/pulseaudio " + " https://github.com/lwvmobile/dsd-fme/tree/pulseaudio " }; - int comp (const void *a, const void *b) { @@ -74,6 +73,7 @@ struct stat st = {0}; void noCarrier (dsd_opts * opts, dsd_state * state) { + // state->testcounter = 0; state->dibit_buf_p = state->dibit_buf + 200; memset (state->dibit_buf, 0, sizeof (int) * 200); //dmr buffer @@ -133,8 +133,6 @@ noCarrier (dsd_opts * opts, dsd_state * state) mbe_initMbeParms (state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2); state->dmr_ms_mode = 0; - state->dropL = 256; //drop it like its hot - state->dropR = 256; //drop it like its hot //not sure if desirable here or not just yet, may need to disable a few of these state->payload_mi = 0; @@ -145,12 +143,49 @@ noCarrier (dsd_opts * opts, dsd_state * state) state->payload_algidR = 0; state->payload_keyid = 0; state->payload_keyidR = 0; - //just for a test - if (state->M == 0) + + state->payload_miN = 0; + state->p25vc = 0; + state->payload_miP = 0; + + //initialize dmr data header source + state->dmr_lrrp_source[0] = 0; + state->dmr_lrrp_source[1] = 0; + + //initialize 12 rate superframe + for (short i = 0; i < 288; i++) { - state->K = 0; + state->dmr_12_rate_sf[0][i] = 0; + state->dmr_12_rate_sf[1][i] = 0; } + //initialize 34 rate superframe + for (short i = 0; i < 288; i++) + { + state->dmr_34_rate_sf[0][i] = 0; + state->dmr_34_rate_sf[1][i] = 0; + } + + //initialize data header bits + state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header + state->data_header_blocks[1] = 1; //when trying to fill the superframe and 0-1 blocks give us an overflow + state->data_header_padding[0] = 0; + state->data_header_padding[1] = 0; + state->data_header_format[0] = 0; + state->data_header_format[1] = 0; + state->data_header_sap[0] = 0; + state->data_header_sap[1] = 0; + state->data_block_counter[0] = 0; + state->data_block_counter[1] = 0; + state->data_p_head[0] = 0; + state->data_p_head[1] = 0; + + // state->dmr_so = 0; //let TLC or Voice LC/Burst zero or set this instead? + // state->dmr_soR = 0; + + state->dmr_encL = 0; + state->dmr_encR = 0; + } void @@ -172,15 +207,15 @@ initOpts (dsd_opts * opts) //sprintf (opts->audio_in_dev, "/dev/audio"); sprintf (opts->audio_in_dev, "pulse"); opts->audio_in_fd = -1; -#ifdef USE_PORTAUDIO - opts->audio_in_pa_stream = NULL; -#endif +// #ifdef USE_PORTAUDIO +// opts->audio_in_pa_stream = NULL; +// #endif //sprintf (opts->audio_out_dev, "/dev/audio"); sprintf (opts->audio_out_dev, "pulse"); opts->audio_out_fd = -1; -#ifdef USE_PORTAUDIO - opts->audio_out_pa_stream = NULL; -#endif +// #ifdef USE_PORTAUDIO +// opts->audio_out_pa_stream = NULL; +// #endif opts->split = 0; opts->playoffset = 0; opts->playoffsetR = 0; @@ -192,7 +227,16 @@ initOpts (dsd_opts * opts) opts->audio_gainR = 0; opts->audio_out = 1; opts->wav_out_file[0] = 0; + opts->wav_out_fileR[0] = 0; + opts->wav_out_file_raw[0] = 0; + opts->symbol_out_file[0] = 0; + opts->symbol_out_f = NULL; + opts->symbol_out = 0; opts->wav_out_f = NULL; + opts->wav_out_fR = NULL; + opts->wav_out_raw = NULL; + + opts->dmr_stereo_wav = 0; //flag for per call dmr stereo wav recordings //opts->wav_out_fd = -1; opts->serial_baud = 115200; sprintf (opts->serial_dev, "/dev/ttyUSB0"); @@ -200,6 +244,7 @@ initOpts (dsd_opts * opts) opts->frame_dstar = 1; opts->frame_x2tdma = 1; opts->frame_p25p1 = 1; + opts->frame_p25p2 = 0; opts->frame_nxdn48 = 0; opts->frame_nxdn96 = 0; opts->frame_dmr = 1; @@ -225,10 +270,11 @@ initOpts (dsd_opts * opts) opts->rtl_udp_port = 6020; //set UDP port for RTL remote opts->rtl_bandwidth = 12; //changed recommended default to 12, 24 for ProVoice opts->rtlsdr_ppm_error = 0; //initialize ppm with 0 value; bug reported by N. + opts->rtl_started = 0; opts->pulse_raw_rate_in = 48000; - opts->pulse_raw_rate_out = 48000; //doing tests with 2 channels at 24000 for 48000 audio default in pulse + opts->pulse_raw_rate_out = 48000; // opts->pulse_digi_rate_in = 48000; - opts->pulse_digi_rate_out = 48000; //need to copy this to rtl type in and change rate out to 8000 + opts->pulse_digi_rate_out = 8000; // reverted to 8/1, crisper sound, dmr stereo will switch to 24/2 opts->pulse_raw_in_channels = 1; opts->pulse_raw_out_channels = 1; opts->pulse_digi_in_channels = 1; //2 @@ -237,9 +283,9 @@ initOpts (dsd_opts * opts) sprintf (opts->output_name, "Auto Detect"); opts->pulse_flush = 1; //set 0 to flush, 1 for flushed opts->use_ncurses_terminal = 0; + opts->ncurses_compact = 0; + opts->ncurses_history = 1; 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 @@ -247,6 +293,10 @@ initOpts (dsd_opts * opts) opts->audio_in_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized opts->audio_out_type = 0; //this was never initialized, causes issues on rPI 64 (bullseye) if not initialized + opts->lrrp_file_output = 0; + + opts->dmr_mute_encL = 1; + opts->dmr_mute_encR = 1; } @@ -255,6 +305,7 @@ initState (dsd_state * state) { int i, j; + // state->testcounter = 0; state->last_dibit = 0; state->dibit_buf = malloc (sizeof (int) * 1000000); state->dibit_buf_p = state->dibit_buf + 200; @@ -313,6 +364,7 @@ initState (dsd_state * state) sprintf (state->fsubtype, " "); sprintf (state->ftype, " "); state->symbolcnt = 0; + state->symbolc = 0; // state->rf_mod = 0; state->numflips = 0; state->lastsynctype = -1; @@ -377,6 +429,7 @@ initState (dsd_state * state) state->nxdn_cipher_type = 0; state->nxdn_key = 0; sprintf (state->nxdn_call_type, " "); + state->payload_miN = 0; state->dpmr_color_code = -1; state->dpmr_caller_id = 0; @@ -419,7 +472,7 @@ initState (dsd_state * state) state->K = 0; state->R = 0; - state->M = 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 @@ -429,11 +482,49 @@ initState (dsd_state * state) state->dmr_fidR = 0; state->dmr_ms_mode = 0; - state->dropL = 256; //drop it like its hot - state->dropR = 256; //drop it like its hot + state->p25vc = 0; + + state->payload_miP = 0; memset(state->dstarradioheader, 0, 41); + //initialize dmr data header source + state->dmr_lrrp_source[0] = 0; + state->dmr_lrrp_source[1] = 0; + + //initialize 12 rate superframe + for (short i = 0; i < 288; i++) + { + state->dmr_12_rate_sf[0][i] = 0; + state->dmr_12_rate_sf[1][i] = 0; + } + + //initialize 34 rate superframe + for (short i = 0; i < 288; i++) + { + state->dmr_34_rate_sf[0][i] = 0; + state->dmr_34_rate_sf[1][i] = 0; + } + + //initialize data header bits + state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header + state->data_header_blocks[1] = 1; //when trying to fill the superframe and 0-1 blocks give us an overflow + state->data_header_padding[0] = 0; + state->data_header_padding[1] = 0; + state->data_header_format[0] = 0; + state->data_header_format[1] = 0; + state->data_header_sap[0] = 0; + state->data_header_sap[1] = 0; + state->data_block_counter[0] = 0; + state->data_block_counter[1] = 0; + state->data_p_head[0] = 0; + state->data_p_head[1] = 0; + + state->menuopen = 0; //is the ncurses menu open, if so, don't process frame sync + + state->dmr_encL = 0; + state->dmr_encR = 0; + #ifdef TRACE_DSD state->debug_sample_index = 0; state->debug_label_file = NULL; @@ -447,14 +538,15 @@ initState (dsd_state * state) void usage () { - //printf ( "Github Build Version: %s \n", GIT_TAG); - //printf ( "2022 Dove Award Recipient"); //Thanks, Scott + printf ("\n"); - printf ("Usage: dsd [options] Live scanner mode\n"); - printf (" or: dsd [options] -r Read/Play saved mbe data from file(s)\n"); - printf (" or: dsd -h Show help\n"); + printf ("Usage: dsd-fme [options] Live scanner mode\n"); + printf (" or: dsd-fme [options] -r Read/Play saved mbe data from file(s)\n"); + printf (" or: dsd-fme -h Show help\n"); printf ("\n"); printf ("Display Options:\n"); + printf (" -N Use NCurses Terminal\n"); + printf (" -use with 2> log.txt at end of command\n"); printf (" -e Show Frame Info and errorbars (default)\n"); printf (" -pe Show P25 encryption sync bits\n"); printf (" -pl Show P25 link control bits\n"); @@ -474,7 +566,7 @@ usage () printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); printf (" -w Output synthesized speech to a .wav file\n"); //printf (" -a Display port audio devices\n"); - printf (" -W Monitor Source Audio When No Sync Detected (WIP!)\n"); + //printf (" -W Monitor Source Audio When No Sync Detected (WIP!)\n"); printf ("\n"); printf ("RTL-SDR options:\n"); printf (" -c RTL-SDR Frequency\n"); @@ -495,43 +587,38 @@ usage () printf (" -fa Auto-detect frame type (default)\n"); printf (" -f1 Decode only P25 Phase 1\n"); printf (" -fd Decode only D-STAR\n"); - printf (" -fr Decode only DMR/MOTOTRBO\n"); + printf (" -fr Decode only DMR\n"); printf (" -fx Decode only X2-TDMA\n"); printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); printf (" -fn Decode only NXDN96* (12.5 kHz)\n"); printf (" -fp Decode only ProVoice*\n"); printf (" -fm Decode only dPMR*\n"); - printf (" -l Disable DMR/MOTOTRBO and NXDN input filtering\n"); - printf (" -ma Auto-select modulation optimizations (default)\n"); - printf (" -mc Use only C4FM modulation optimizations\n"); - printf (" -mg Use only GFSK modulation optimizations\n"); - printf (" -mq Use only QPSK modulation optimizations\n"); + printf (" -l Disable DMR and NXDN input filtering\n"); printf (" -pu Unmute Encrypted P25\n"); printf (" -u Unvoiced speech quality (default=3)\n"); printf (" -xx Expect non-inverted X2-TDMA signal\n"); - printf (" -xr Expect inverted DMR/MOTOTRBO signal\n"); + printf (" -xr Expect inverted DMR signal\n"); printf (" -xd Expect inverted ICOM dPMR signal\n"); //still need to do this printf ("\n"); printf (" * denotes frame types that cannot be auto-detected.\n"); printf ("\n"); - printf ("Advanced decoder options:\n"); - printf (" -A QPSK modulation auto detection threshold (default=26)\n"); + printf ("Advanced Decoder options:\n"); + // printf (" -A QPSK modulation auto detection threshold (default=26)\n"); printf (" -S Symbol buffer size for QPSK decision point tracking\n"); printf (" (default=36)\n"); printf (" -M Min/Max buffer size for QPSK decision point tracking\n"); printf (" (default=15)\n"); - printf (" -n Reset P25 Heuristics and initState variables on mixed signal decoding\n"); - printf (" Helps when decoding mixed signal types (P25P1) at same time\n"); - printf (" (WiP! May Cause Slow Memory Leak or System Hang - Experimental)\n"); + // printf (" -n Reset P25 Heuristics and initState variables on mixed signal decoding\n"); + // printf (" Helps when decoding mixed signal types (P25P1) at same time\n"); + // printf (" (WiP! May Cause Slow Memory Leak or System Hang - Experimental)\n"); printf (" -T Enable DMR TDMA Stereo Voice (Two Slot Dual Voices)\n"); printf (" This feature will open two streams for slot 1 voice and slot 2 voice\n"); printf (" May Cause Skipping or sync issues if bad signal/errors\n"); printf (" -F Enable DMR TDMA Stereo Passive Frame Sync\n"); printf (" This feature will attempt to resync less often due to excessive voice errors\n"); printf (" Use if skipping occurs, but may cause wonky audio due to loss of good sync\n"); - printf (" -Z Log MBE Payload to console\n"); + printf (" -Z Log MBE/Frame Payloads to console\n"); printf ("\n"); - printf ("Report bugs to: https://github.com/lwvmobile/dsd-fme/issues \n"); exit (0); } @@ -539,8 +626,6 @@ void liveScanner (dsd_opts * opts, dsd_state * state) { -//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; //revert to 8K/1 for STDIN input, sometimes crackles when upsampling @@ -557,19 +642,6 @@ if (opts->audio_in_type == 1) } -#ifdef USE_PORTAUDIO - if(opts->audio_in_type == 2) - { - PaError err = Pa_StartStream( opts->audio_in_pa_stream ); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while starting the portaudio input stream\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - return; - } - } -#endif #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { @@ -588,28 +660,38 @@ if (opts->audio_in_type == 1) opts->pulse_raw_out_channels = 1; open_rtlsdr_stream(opts); + opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again } #endif + +if (opts->use_ncurses_terminal == 1) +{ + ncursesOpen(opts, state); +} + if (opts->audio_in_type == 0) { openPulseInput(opts); } + if (opts->audio_out_type == 0) { openPulseOutput(opts); } - while (1) { noCarrier (opts, state); + if (state->menuopen == 0) + { + state->synctype = getFrameSync (opts, state); + // recalibrate center/umid/lmid + 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; + } - state->synctype = getFrameSync (opts, state); - // recalibrate center/umid/lmid - 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; while (state->synctype != -1) @@ -620,16 +702,24 @@ if (opts->audio_out_type == 0) state->debug_prefix = 'S'; #endif - state->synctype = getFrameSync (opts, state); + // state->synctype = getFrameSync (opts, state); #ifdef TRACE_DSD state->debug_prefix = '\0'; #endif - // recalibrate center/umid/lmid - 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; + // // recalibrate center/umid/lmid + // 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; + if (state->menuopen == 0) + { + state->synctype = getFrameSync (opts, state); + // recalibrate center/umid/lmid + 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; + } } } } @@ -639,59 +729,33 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state) { noCarrier (opts, state); if (opts->wav_out_f != NULL) - { - closeWavOutFile (opts, state); - } - -#ifdef USE_PORTAUDIO - if((opts->audio_in_type == 2) || (opts->audio_out_type == 2)) - { - fprintf (stderr,"Terminating portaudio.\n"); - PaError err = paNoError; - if(opts->audio_in_pa_stream != NULL) - { - err = Pa_CloseStream( opts->audio_in_pa_stream ); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while closing the portaudio input stream\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } - } - if(opts->audio_out_pa_stream != NULL) - { - err = Pa_IsStreamActive( opts->audio_out_pa_stream ); - if(err == 1) - err = Pa_StopStream( opts->audio_out_pa_stream ); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while closing the portaudio output stream\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } - err = Pa_CloseStream( opts->audio_out_pa_stream ); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while closing the portaudio output stream\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } - } - err = Pa_Terminate(); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while terminating portaudio\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - } - } -#endif + { + closeWavOutFile (opts, state); + } + if (opts->wav_out_raw != NULL) + { + closeWavOutFileRaw (opts, state); + } + if (opts->dmr_stereo_wav == 1) + { + closeWavOutFileL (opts, state); + closeWavOutFileR (opts, state); + } + if (opts->symbol_out == 1) + { + closeSymbolOutFile (opts, state); + } + if (opts->mbe_out_f != NULL) + { + closeMbeOutFile (opts, state); + } #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { // TODO: cleanup demod threads - cleanup_rtlsdr_stream(); + //temp disable to see if this corrects issues with closing + //cleanup_rtlsdr_stream(); } #endif @@ -775,15 +839,15 @@ main (int argc, char **argv) char versionstr[25]; mbe_printVersion (versionstr); - - for (short int i = 0; i < 7; i++) { - fprintf (stderr,"%s%s \n", FM_banner[i], KCYN); //cyan/blue text + fprintf (stderr," Digital Speech Decoder: Florida Man Edition\n"); + for (short int i = 1; i < 7; i++) { + //fprintf (stderr,"%s%s \n", FM_banner[i], KGRN); //cyan/blue text + fprintf (stderr,"%s\n", FM_banner[i]); //cyan/blue tex } - fprintf (stderr,"%s", KNRM); //change back to normal - fprintf (stderr, "%s \n", FM_banner[7]); - fprintf (stderr,"Digital Speech Decoder: Florida Man Edition\n"); + //fprintf (stderr,"%s", KNRM); //change back to normal + fprintf (stderr, "Github Build Version: %s \n", GIT_TAG); - fprintf (stderr,"mbelib version %s\n", versionstr); + fprintf (stderr,"MBElib version %s\n", versionstr); initOpts (&opts); initState (&state); @@ -793,7 +857,7 @@ main (int argc, char **argv) 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:NWrlZTF")) != -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:NQWrlZTF")) != -1) { opterr = 0; switch (c) @@ -802,7 +866,7 @@ main (int argc, char **argv) usage (); exit (0); case 'a': - printPortAudioDevices(); + //printPortAudioDevices(); exit(0); case 'e': opts.errorbars = 1; @@ -832,7 +896,8 @@ main (int argc, char **argv) } break; case 'P': - sscanf (optarg, "%i", &opts.rtlsdr_ppm_error); + //can't handle negative numbers? + //sscanf (optarg, "%d", &opts.rtlsdr_ppm_error); break; case 'q': opts.errorbars = 0; @@ -858,15 +923,17 @@ main (int argc, char **argv) case 'K': sscanf (optarg, "%lld", &state.K); - state.M = 1; if (state.K > 256) { state.K = 256; } - break; - - case 'R': - sscanf (optarg, "%lld", &state.R); + opts.dmr_mute_encL = 0; + opts.dmr_mute_encR = 0; + if (state.K == 1) + { + opts.dmr_mute_encL = 1; + opts.dmr_mute_encR = 1; + } break; case 'G': //Set rtl device gain @@ -877,11 +944,11 @@ main (int argc, char **argv) sscanf (optarg, "%d", &opts.rtl_squelch_level); //set squelch by user to prevent false positives on NXDN and others break; - case 'V': //Set rtl squelch level + case 'V': //Set rtl voltage level sscanf (optarg, "%d", &opts.rtl_volume_multiplier); //set 'volume' multiplier for rtl-sdr samples break; - case 'U': //Set rtl squelch level + case 'U': //Set rtl udp remote port sscanf (optarg, "%d", &opts.rtl_udp_port); //set udp port number for RTL remote break; @@ -893,23 +960,20 @@ main (int argc, char **argv) sscanf (optarg, "%d", &opts.rtl_bandwidth); break; - 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': opts.use_ncurses_terminal = 1; fprintf (stderr,"Enabling NCurses Terminal.\n"); - fprintf (stderr," - may need to issue 'reset' command in terminal after use\n"); + //fprintf (stderr," - may need to issue 'reset' command in terminal after use\n"); break; case 'Z': opts.payload = 1; - fprintf (stderr,"Logging MBE Payload to console\n"); + fprintf (stderr,"Logging Frame Payload to console\n"); + break; + + case 'Q': + opts.lrrp_file_output = 1; + fprintf (stderr,"Logging LRRP data to ~/lrrp.txt \n"); break; case 'T': @@ -917,16 +981,18 @@ main (int argc, char **argv) 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); + sprintf (opts.output_name, "DMR STEREO"); + fprintf (stderr, "%s", KYEL); fprintf (stderr,"DMR Stereo Sync and Functionality Enabled.\n"); - fprintf (stderr,"DMR Stereo will disable WAV and MBE file saving!\n"); + fprintf (stderr,"DMR Stereo will disable MBE file saving!\n"); + fprintf (stderr,"DMR Stereo per call WAV file can be enabled in the NCurses Terminal!\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, "%s", KYEL); fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n"); fprintf (stderr, "%s", KNRM); break; @@ -984,32 +1050,28 @@ main (int argc, char **argv) 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," -(Disabled until memory leak issues can be resolved!)\n"); - fprintf (stderr, "%s", KNRM); - break; + case 'w': strncpy(opts.wav_out_file, optarg, 1023); opts.wav_out_file[1023] = '\0'; - fprintf (stderr,"Writing + Appending audio to file %s\n", opts.wav_out_file); + fprintf (stderr,"Writing + Appending decoded audio to file %s\n", opts.wav_out_file); openWavOutFile (&opts, &state); break; + case 'B': sscanf (optarg, "%d", &opts.serial_baud); break; + case 'C': strncpy(opts.serial_dev, optarg, 1023); opts.serial_dev[1023] = '\0'; break; - //case 'R': - // sscanf (optarg, "%d", &opts.resume); - // fprintf (stderr,"Enabling scan resume after %i TDULC frames\n", opts.resume); - // break; + + case 'R': + sscanf (optarg, "%d", &opts.resume); + fprintf (stderr,"Enabling scan resume after %i TDULC frames\n", opts.resume); + break; + case 'f': if (optarg[0] == 'a') { @@ -1017,7 +1079,7 @@ main (int argc, char **argv) opts.frame_x2tdma = 1; opts.frame_p25p1 = 1; opts.frame_nxdn48 = 0; - opts.frame_nxdn96 = 0; //causes false positives, leave on 0 + opts.frame_nxdn96 = 0; opts.frame_dmr = 1; opts.frame_dpmr = 0; opts.frame_provoice = 0; @@ -1033,6 +1095,7 @@ main (int argc, char **argv) opts.frame_dmr = 0; opts.frame_dpmr = 0; opts.frame_provoice = 0; + state.rf_mod = 0; sprintf (opts.output_name, "D-STAR"); fprintf (stderr,"Decoding only D-STAR frames.\n"); } @@ -1104,7 +1167,6 @@ main (int argc, char **argv) opts.mod_gfsk = 0; state.rf_mod = 0; sprintf (opts.output_name, "NXDN48"); - //opts.symboltiming = 2400; //NXDN48 uses 2400 symbol rate fprintf (stderr,"Setting symbol rate to 2400 / second\n"); fprintf (stderr,"Decoding only NXDN 4800 baud frames.\n"); } @@ -1113,23 +1175,44 @@ main (int argc, char **argv) opts.frame_dstar = 0; opts.frame_x2tdma = 0; opts.frame_p25p1 = 0; + opts.frame_p25p2 = 0; opts.frame_nxdn48 = 0; opts.frame_nxdn96 = 0; opts.frame_dmr = 0; opts.frame_dpmr = 0; opts.frame_provoice = 0; opts.frame_ysf = 1; - state.samplesPerSymbol = 10; - //state.symbolCenter = 10; + state.samplesPerSymbol = 20; //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] == '2') + { + opts.frame_dstar = 0; + opts.frame_x2tdma = 0; + opts.frame_p25p1 = 0; + opts.frame_p25p2 = 1; + opts.frame_nxdn48 = 0; + opts.frame_nxdn96 = 0; + opts.frame_dmr = 0; + opts.frame_dpmr = 0; + opts.frame_provoice = 0; + opts.frame_ysf = 0; + state.samplesPerSymbol = 20; //10 + state.symbolCenter = 10; + opts.mod_c4fm = 0; + opts.mod_qpsk = 1; + opts.mod_gfsk = 0; + state.rf_mod = 0; + sprintf (opts.output_name, "P25-P2"); + fprintf (stderr,"Decoding P25-P2 frames.\nNot working yet!\n"); + } else if (optarg[0] == 'n') { opts.frame_dstar = 0; @@ -1161,9 +1244,9 @@ main (int argc, char **argv) opts.mod_qpsk = 0; opts.mod_gfsk = 0; // state.rf_mod = 0; // - sprintf (opts.output_name, "DMR/MOTOTRBO"); + sprintf (opts.output_name, "DMR LEH"); //fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n"); - fprintf (stderr,"Decoding only DMR/MOTOTRBO frames.\n"); + fprintf (stderr,"Decoding only DMR frames.\n"); } else if (optarg[0] == 'm') { @@ -1242,7 +1325,7 @@ main (int argc, char **argv) else if (optarg[0] == 'r') { opts.inverted_dmr = 1; - fprintf (stderr,"Expecting inverted DMR/MOTOTRBO signals.\n"); + fprintf (stderr,"Expecting inverted DMR signals.\n"); } else if (optarg[0] == 'd') { @@ -1253,7 +1336,6 @@ main (int argc, char **argv) case 'A': sscanf (optarg, "%i", &opts.mod_threshold); fprintf (stderr,"Setting C4FM/QPSK auto detection threshold to %i\n", opts.mod_threshold); - break; case 'S': sscanf (optarg, "%i", &opts.ssize); if (opts.ssize > 128) @@ -1294,11 +1376,6 @@ main (int argc, char **argv) } } - if (opts.use_ncurses_terminal == 1) - { - ncursesOpen(); - } - if (opts.resume > 0) { openSerial (&opts, &state); @@ -1314,23 +1391,7 @@ main (int argc, char **argv) opts.audio_out_type == 0; } -#ifdef USE_PORTAUDIO - if((strncmp(opts.audio_in_dev, "pa:", 3) == 0) - || (strncmp(opts.audio_out_dev, "pa:", 3) == 0)) - { - fprintf (stderr,"Initializing portaudio.\n"); - PaError err = Pa_Initialize(); - if( err != paNoError ) - { - //fprintf (stderr, "An error occured while initializing portaudio\n" ); - //fprintf (stderr, "Error number: %d\n", err ); - //fprintf (stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - exit(err); - } - } -#endif - - if (opts.playfiles == 1) + if (opts.playfiles == 1) { opts.split = 1; opts.playoffset = 0; @@ -1345,7 +1406,7 @@ main (int argc, char **argv) openAudioOutDevice (&opts, SAMPLE_RATE_OUT); } } - else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) + else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) { opts.split = 1; opts.playoffset = 0; @@ -1368,16 +1429,15 @@ main (int argc, char **argv) else { opts.split = 0; - opts.playoffset = 25; // 38 - opts.playoffsetR = 25; // 38 + opts.playoffset = 25; + opts.playoffsetR = 25; opts.delay = 0; - openAudioInDevice (&opts); //disabled all four instances of openAudio devices, in and out for now + openAudioInDevice (&opts); opts.audio_out_fd = opts.audio_in_fd; } if (opts.playfiles == 1) { - //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 @@ -1389,9 +1449,6 @@ main (int argc, char **argv) liveScanner (&opts, &state); } - if (opts.use_ncurses_terminal == 1){ - //ncursesClose (); - } cleanupAndExit (&opts, &state); return (0); diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c index 16cc63b..a28a3f9 100644 --- a/src/dsd_mbe.c +++ b/src/dsd_mbe.c @@ -17,10 +17,6 @@ #include "dsd.h" -// -//C -// - void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv) { @@ -117,8 +113,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a }; // - - int i; + int i; char imbe_d[88]; char ambe_d[49]; char ambe_d_str[50]; @@ -141,20 +136,44 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a { // 0 +P25p1 // 1 -P25p1 + state->errs = mbe_eccImbe7200x4400C0 (imbe_fr); + state->errs2 = state->errs; + mbe_demodulateImbe7200x4400Data (imbe_fr); + state->errs2 += mbe_eccImbe7200x4400Data (imbe_fr, imbe_d); - mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + + mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + //mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); if (opts->payload == 1) { PrintIMBEData (opts, state, imbe_d); } + + //increment vc counter by one. + state->p25vc++; + if (opts->mbe_out_f != NULL) { saveImbe4400Data (opts, state, imbe_d); } } - else if ((state->synctype == 14) || (state->synctype == 15)) + else if ((state->synctype == 14) || (state->synctype == 15)) //pV Sync { - mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + state->errs = mbe_eccImbe7100x4400C0 (imbe7100_fr); + state->errs2 = state->errs; + mbe_demodulateImbe7100x4400Data (imbe7100_fr); + state->errs2 += mbe_eccImbe7100x4400Data (imbe7100_fr, imbe_d); + mbe_convertImbe7100to7200(imbe_d); //needs extra conversion step apparently + + mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + //below line the old way of doing this + // mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); if (opts->payload == 1) { PrintIMBEData (opts, state, imbe_d); @@ -176,6 +195,28 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a saveAmbe2450Data (opts, state, ambe_d); } } + else if ((state->synctype == 8) || (state->synctype == 9)) + { + state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr); + state->errs2 = state->errs; + mbe_demodulateAmbe3600x2450Data (ambe_fr); + state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); + + + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + if (opts->payload == 1) + { + PrintAMBEData (opts, state, ambe_d); + } + + if (opts->mbe_out_f != NULL) + { + saveAmbe2450Data (opts, state, ambe_d); + } + + } else { //stereo slots and slot 0 (left slot) @@ -186,28 +227,26 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a state->errs2 = state->errs; mbe_demodulateAmbe3600x2450Data (ambe_fr); state->errs2 += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); - // - //F - // + + // if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0) // { k = BP[state->K]; k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); - for (short int j = 0; j < 49; j++) + for (short int j = 0; j < 48; j++) //49 { x = ( ((k << j) & 0x800000000000) >> 47 ); ambe_d[j] ^= x; } } - // - //D - // - mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, - ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + //old method for this step below //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->payload == 1) + if (opts->payload == 1) // && state->R == 0 this is why slot 1 didn't primt abme, probably had it set during testing { PrintAMBEData (opts, state, ambe_d); } @@ -220,24 +259,21 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a state->errs2R = state->errsR; mbe_demodulateAmbe3600x2450Data (ambe_fr); state->errs2R += mbe_eccAmbe3600x2450Data (ambe_fr, ambe_d); - // - //G - // + + //BP Handling, Slot 2 if (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0) // { k = BP[state->K]; k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k ); - for (short int j = 0; j < 49; j++) + for (short int j = 0; j < 48; j++) { x = ( ((k << j) & 0x800000000000) >> 47 ); ambe_d[j] ^= x; } } - // - //E - // - mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR, - ambe_d, state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2, opts->uvquality); + + mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, &state->errsR, &state->errs2R, state->err_strR, + ambe_d, state->cur_mp2, state->prev_mp2, state->prev_mp_enhanced2, opts->uvquality); //old method for this step below //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); @@ -246,7 +282,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a PrintAMBEData (opts, state, ambe_d); } } - //if using older DMR method, dPMR, or NXDN + + //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types 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); @@ -254,7 +291,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a { PrintAMBEData (opts, state, ambe_d); } - if (opts->mbe_out_f != NULL) + //only save MBE files if not enc or unmuted, THIS does not seem to work for some reason + if (opts->mbe_out_f != NULL && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) { saveAmbe2450Data (opts, state, ambe_d); } @@ -263,35 +301,88 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a } - state->debug_audio_errors += state->errs2; - state->debug_audio_errorsR += state->errs2R; + //having these values here I think caused muddy audio, seems cleaner now when moved to correct area + // state->debug_audio_errors += state->errs2; + // state->debug_audio_errorsR += state->errs2R; + + //quick enc check to determine whether or not to play enc traffic + int enc_bit = 0; + //end enc check + if (opts->dmr_stereo == 1 && state->currentslot == 0) { - processAudio (opts, state); - if (opts->audio_out == 1) + enc_bit = (state->dmr_so >> 6) & 0x1; + if (enc_bit == 1) { - playSynthesizedVoice (opts, state); + state->dmr_encL = 1; + } + else state->dmr_encL = 0; + if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) + { + state->debug_audio_errors += state->errs2; + 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) + enc_bit = (state->dmr_soR >> 6) & 0x1; + if (enc_bit == 0x1) { - playSynthesizedVoiceR (opts, state); + state->dmr_encR = 1; + } + else state->dmr_encR = 0; + if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) + { + state->debug_audio_errorsR += state->errs2R; + processAudioR (opts, state); + if (opts->audio_out == 1) + { + playSynthesizedVoiceR (opts, state); + } } } - if (opts->dmr_stereo == 0) + + //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types + if (opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) ) { + state->debug_audio_errors += state->errs2; processAudio (opts, state); if (opts->audio_out == 1) { playSynthesizedVoice (opts, state); } } - if (opts->wav_out_f != NULL && opts->dmr_stereo == 0) + + //if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types + if (opts->wav_out_f != NULL && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0)) { writeSynthesizedVoice (opts, state); } + //per call can only be used when ncurses terminal is active since we use its call history matrix for when to record + if (opts->use_ncurses_terminal == 1 && opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 0) + { + if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) + { + //write wav to per call on left channel Slot 1 + writeSynthesizedVoice (opts, state); + } + } + + //per call can only be used when ncurses terminal is active since we use its call history matrix for when to record + if (opts->use_ncurses_terminal == 1 && opts->dmr_stereo_wav == 1 && opts->dmr_stereo == 1 && state->currentslot == 1) + { + if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) + { + //write wav to per call on right channel Slot 2 + writeSynthesizedVoiceR (opts, state); + } + } + + } diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index d8b691a..d980ddb 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -1,12 +1,12 @@ /*------------------------------------------------------------------------------- * dsd_ncurses.c - * A dsd ncurses terminal printer + * A dsd ncurses terminal printer with menu system * * ASCII art generated by: * https://fsymbols.com/generators/carty/ * * LWVMOBILE - * 2022-02 DSD-FME Florida Man Edition + * 2022-08 DSD-FME Florida Man Edition *-----------------------------------------------------------------------------*/ /* * Copyright (C) 2010 DSD Author @@ -28,8 +28,26 @@ #include "dsd.h" #include "git_ver.h" +//UDP Remote +#include +// #include +#include + +#define BSIZE 999 +#define UDP_BUFLEN 5 //maximum UDP buffer length +#define SRV_IP "127.0.0.1" //IP +#define UDP_PORT 6020 //UDP port + +int handle; //for UDP +unsigned short udp_port = UDP_PORT; +char data[UDP_BUFLEN] = {0}; +struct sockaddr_in address; + +uint32_t temp_freq = -1; +// + int reset = 0; -char c; //getch key + int tg; int tgR; int tgn; @@ -43,19 +61,21 @@ int dcc = -1; int i = 0; char versionstr[25]; unsigned long long int call_matrix[33][6]; - +//current news story for tagline +//https://www.vice.com/en/article/epzzdk/florida-man-arrested-trying-to-warn-space-force-base-of-alien-dragon-war char * FM_bannerN[9] = { - " 2022 Dove Award Winner CTRL + C twice to exit", - " ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗", - " ██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝", - " ██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ ", - " ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ", - " ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗", - " ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝", - "https://github.com/lwvmobile/dsd-fme/tree/pulseaudio " + " ESC or Arrow Keys For Menu ", + " ██████╗ ██████╗██████╗    ███████╗███╗ ███╗███████╗ 'Florida Man steals", + " ██╔══██╗██╔════╝██╔══██╗   ██╔════╝████╗ ████║██╔════╝ Truck; Drives to ", + " ██║ ██║╚█████╗ ██║ ██║   █████╗ ██╔████╔██║█████╗ Space Force to warn", + " ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ warn of war between", + " ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗ Aliens and Chinese ", + " ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝ Dragons' - FM News ", + " ", + " " }; -char * SyncTypes[36] = { +char * SyncTypes[38] = { "+P25P1", "-P25P1", "+X2TDMA DATA", @@ -90,7 +110,9 @@ char * SyncTypes[36] = { "-YSF", "DMR MS VOICE", "DMR MS DATA", - "DMR RC DATA" + "DMR RC DATA", + "+P25-P2", + "-P25-P2" }; char * DMRBusrtTypes[18] = { @@ -115,6 +137,18 @@ char * DMRBusrtTypes[18] = { }; +char * getDateN(void) { + char datename[99]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text + char * curr2; + struct tm * to; + time_t t; + t = time(NULL); + to = localtime( & t); + strftime(datename, sizeof(datename), "%Y-%m-%d", to); + curr2 = strtok(datename, " "); + return curr2; +} + time_t nowN; char * getTimeN(void) //get pretty hh:mm:ss timestamp { @@ -131,8 +165,127 @@ char * getTimeN(void) //get pretty hh:mm:ss timestamp return curr; } -void ncursesOpen () +//testing a few things, going to put this into ncursesMenu +#define WIDTH 36 +#define HEIGHT 23 + +int startx = 0; +int starty = 0; + +char *choicesc[] = { + "Return", + "Save Decoded Audio WAV (NO DMR STEREO!)", + "Save Signal to Symbol Capture Bin", + "Toggle Muting Enrypted Traffic ", + "Per Call WAV REC (DMR Stereo/MS)", + "Setup and Start RTL Input ", + "Pulse Audio 48kHz Output", + "Pulse Audio 8kHz Output (NO DMR STEREO!)", + "Reset States and Heuristics", + "Toggle NCurses Compact Mode", + "Toggle NCurses Call History", + "Stop All Decoded WAV Saving", + "Read OP25/FME Symbol Capture Bin", + "Replay Last Symbol Capture Bin", + "Stop & Close Symbol Capture Bin Playback", + "Stop & Close Symbol Capture Bin Saving", + "Retune RTL Dongle", + "Resume Decoding" + }; + +char *choices[] = { + "Resume Decoding", + "Decode Auto**", + "Decode ProVoice", + "Decode D-STAR*", + "Decode P25-P1*", + "Decode DMR (STEREO BS/MS)", + "Decode DMR* (LEH)", + "Decode dPMR", + "Decode NXDN48", + "Decode NXDN96", + "Decode X2-TDMA*", + "Toggle Signal Inversion", + " ", //spacer + "Reset Call History", + "Enable Payloads to Console", + "Disable Payloads to Console", + "Input & Output Options", + "Enable LRRP to ~/lrrp.txt", + "Exit DSD-FME", + // "Test" + }; + + +int n_choices = sizeof(choices) / sizeof(char *); +// int n_choicesb = sizeof(choicesb) / sizeof(char *); +int n_choicesc = sizeof(choicesc) / sizeof(char *); + +void print_menu(WINDOW *menu_win, int highlight) { + int x, y, i; + + x = 2; + y = 2; + box(menu_win, 0, 0); + for(i = 0; i < n_choices; ++i) + { if(highlight == i + 1) /* High light the present choice */ + { wattron(menu_win, A_REVERSE); + mvwprintw(menu_win, y, x, "%s", choices[i]); + wattroff(menu_win, A_REVERSE); + } + else + mvwprintw(menu_win, y, x, "%s", choices[i]); + ++y; + } + wrefresh(menu_win); +} + +// void print_menub(WINDOW *menu_win, int highlight) +// { +// int x, y, i; +// +// x = 2; +// y = 2; +// box(menu_win, 0, 0); +// for(i = 0; i < n_choicesb; ++i) +// { if(highlight == i + 1) /* High light the present choice */ +// { wattron(menu_win, A_REVERSE); +// mvwprintw(menu_win, y, x, "%s", choicesb[i]); +// wattroff(menu_win, A_REVERSE); +// } +// else +// mvwprintw(menu_win, y, x, "%s", choicesb[i]); +// ++y; +// } +// wrefresh(menu_win); +// } + +void print_menuc(WINDOW *menu_win, int highlight) +{ + int x, y, i; + + x = 2; + y = 2; + box(menu_win, 0, 0); + for(i = 0; i < n_choicesc; ++i) + { if(highlight == i + 1) /* High light the present choice */ + { wattron(menu_win, A_REVERSE); + mvwprintw(menu_win, y, x, "%s", choicesc[i]); + wattroff(menu_win, A_REVERSE); + } + else + mvwprintw(menu_win, y, x, "%s", choicesc[i]); + ++y; + } + wrefresh(menu_win); +} + +//end Testing + +void ncursesOpen (dsd_opts * opts, dsd_state * state) +{ + // state->menuopen = 1; //flag the menu is open, stop processing getFrameSync mbe_printVersion (versionstr); setlocale(LC_ALL, ""); initscr(); //Initialize NCURSES screen window @@ -142,33 +295,931 @@ void ncursesOpen () init_pair(3, COLOR_GREEN, COLOR_BLACK); //Green for Active Calls init_pair(4, COLOR_CYAN, COLOR_BLACK); //Cyan for Site Extra and Patches init_pair(5, COLOR_MAGENTA, COLOR_BLACK); //Magenta for no frame sync/signal + init_pair(6, COLOR_WHITE, COLOR_BLACK); //White Card Color Scheme noecho(); cbreak(); } +//ncursesMenu +void ncursesMenu (dsd_opts * opts, dsd_state * state) +{ + // state->menuopen = 1; //flag the menu is open, stop processing getFrameSync + closePulseOutput (opts); + + if (opts->audio_in_type == 0) //close pulse input if it is the specified input method + { + closePulseInput(opts); + } + + if (opts->audio_in_type == 3) + { + //function hangs, figure out why I can't release/stop the dongle + //cleanup_rtlsdr_stream(); //close down the rtl dongle + //rtlsdr_sighandler(); + } + + state->payload_keyid = 0; + state->payload_keyidR = 0; + + //zero out to fix call history 'scrolling' bug when changing decoding types + state->nxdn_last_tg = 0; + state->nxdn_last_ran = 0; + state->nxdn_last_rid = 0; + + WINDOW *menu_win; + WINDOW *test_win; + WINDOW *entry_win; + WINDOW *info_win; + int highlight = 1; + int highlightb = 1; + int highlightc = 1; + int choice = 0; + int choiceb = 0; + int choicec = 0; + int c; + int d; + int e; + + startx = 2; + starty = 1; + + menu_win = newwin(HEIGHT, WIDTH, starty, startx); + keypad(menu_win, TRUE); + mvprintw(0, 0, " Use arrow keys to go up and down, Press ENTER to select a choice."); + refresh(); + print_menu(menu_win, highlight); + while(1) + { c = wgetch(menu_win); + switch(c) + { case KEY_UP: + if(highlight == 1) + highlight = n_choices; + else + --highlight; + break; + case KEY_DOWN: + if(highlight == n_choices) + highlight = 1; + else + ++highlight; + break; + case 10: + choice = highlight; + break; + default: + //mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c); + refresh(); + break; + } + + print_menu(menu_win, highlight); + + //test print info boxes on side of certain options + if (highlight == 2) + { + info_win = newwin(6, WIDTH+18, starty, startx+20); + box (info_win, 0, 0); + mvwprintw(info_win, 2, 2, " Auto Decoding can only detect the following:."); + mvwprintw(info_win, 3, 2, " P25-P1, D-STAR, DMR LEH, and X2-TDMA"); + wrefresh(info_win); + } + + //Input Output Options + if (choice == 17) + { + //test making a new window while other window is open + test_win = newwin(HEIGHT-1, WIDTH+9, starty+5, startx+5); + keypad(menu_win, FALSE); + keypad(test_win, TRUE); + mvprintw(0, 0, "Input & Output Options "); + refresh(); + print_menuc(test_win, highlightc); + while(1) + { e = wgetch(test_win); + switch(e) + { case KEY_UP: + if(highlightc == 1) + highlightc = n_choicesc; + else + --highlightc; + break; + case KEY_DOWN: + if(highlightc == n_choicesc) + highlightc = 1; + else + ++highlightc; + break; + case 10: + choicec = highlightc; + break; + default: + //mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c); + refresh(); + break; + } + print_menuc(test_win, highlightc); + if (choicec == 2) + { + sprintf (opts->wav_out_file, "%s %s DSD-FME-DECODED.wav", getDateN(), getTimeN()); + openWavOutFile (opts, state); + } + if (choicec == 3) + { + //read in filename for symbol capture bin + entry_win = newwin(6, WIDTH+16, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter FME Symbol Capture Bin Filename"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%s", &opts->symbol_out_file); + noecho(); + + if (opts->symbol_out_file != NULL) + { + opts->symbol_out = 1; //set flag to 1 + openSymbolOutFile (opts, state); + } + + } + if (choicec == 4) + { + //toggle all mutes + if (opts->unmute_encrypted_p25 == 0) + { + opts->unmute_encrypted_p25 = 1; + } + else opts->unmute_encrypted_p25 = 0; + + if (opts->dmr_mute_encL == 0) + { + opts->dmr_mute_encL = 1; + } + else opts->dmr_mute_encL = 0; + + if (opts->dmr_mute_encR == 0) + { + opts->dmr_mute_encR = 1; + } + else opts->dmr_mute_encR = 0; + + } + if (choicec == 5) + { + opts->dmr_stereo_wav = 1; + //catch all in case of no file name set, won't crash or something + sprintf (opts->wav_out_file, "DSD-FME-SLOT1.wav"); + //sprintf (opts->wav_out_file, "%s %s S1 - CC %d - TG %d - RD %d.wav", getDateN(), getTimeN(), dcc, tg, rd); + sprintf (opts->wav_out_fileR, "DSD-FME-SLOT2.wav"); + //sprintf (opts->wav_out_fileR, "%s %s S2 - CC %d - TG %d - RD %d.wav", getDateN(), getTimeN(), dcc, tg, rd); + openWavOutFileL (opts, state); //testing for now, will want to move to per call later + openWavOutFileR (opts, state); //testing for now, will want to move to per call later + + } + + if (choicec == 6) + { + int confirm = 0; + + #ifdef USE_RTLSDR + + //could also benefit from having some control aside from UDP remote + //BUG: When squelch enabled, all processing halts, no more ncursesprinter until squelch broken + //make another submenu to control these values if tests go well + + entry_win = newwin(6, WIDTH+6, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter RTL Device Index Number"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_dev_index); + noecho(); + + //this is NOT scanning (or printing) in the variable for some reason...why? + entry_win = newwin(6, WIDTH+6, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter RTL Device PPM Error"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtlsdr_ppm_error); + noecho(); + //opts->rtlsdr_ppm_error = -1; //hard set override for testing + + //apparently, scanning in an lld nukes later box entries for some reason + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) "); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); //ld, or lld? + noecho(); + + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter VFO Bandwidth (6, 8, 12, 16, 24, 48)"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_bandwidth); + noecho(); + + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter RTL Gain Value (0-49) (0 = Auto Gain)"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_gain_value); + noecho(); + + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter RTL UDP Remote Port (Default = 6020)"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_udp_port); + noecho(); + if (opts->rtl_udp_port == 0) + { + opts->rtl_udp_port = 6020; + } + + entry_win = newwin(8, WIDTH+22, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter RTL Device Squelch Level or Enter 0"); + mvwprintw(entry_win, 3, 2, " WARNING! Renders Terminal Unresponsive When No Signal!"); + mvwprintw(entry_win, 4, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtl_squelch_level); + noecho(); + + entry_win = newwin(17, WIDTH+20, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Starting RTL Input. Cannot Release/Stop Until Exit."); + mvwprintw(entry_win, 4, 2, " RTL Frequency: %d Hz", opts->rtlsdr_center_freq); + mvwprintw(entry_win, 5, 2, " RTL Device Index Number: %d", opts->rtl_dev_index); + mvwprintw(entry_win, 6, 2, " RTL Device VFO Bandwidth: %d kHz", opts->rtl_bandwidth); + mvwprintw(entry_win, 7, 2, " RTL Device Gain: %d", opts->rtl_gain_value); + mvwprintw(entry_win, 8, 2, " RTL Device UDP Port: %d", opts->rtl_udp_port); + mvwprintw(entry_win, 9, 2, " RTL Device PPM: %d", opts->rtlsdr_ppm_error); + mvwprintw(entry_win, 10, 2, " RTL Device Squelch: %d", opts->rtl_squelch_level); + mvwprintw(entry_win, 12, 2, " Are You Sure?"); + mvwprintw(entry_win, 13, 2, " 1 = Yes, 2 = No "); + mvwprintw(entry_win, 14, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &confirm); + noecho(); + + refresh(); + // opts->rtlsdr_center_freq = 851800000; //test with pV LCN 2 + //opts->rtl_gain_value = 46; + //opts->rtl_dev_index = 1; + // opts->rtl_bandwidth = 24; //12 or 24. + //opts->rtlsdr_ppm_error = -1; + //opts->rtl_udp_port = 6020; + //fprintf (stderr, "Confirm = %d", confirm); + + //works well, but can't release dongle later, so its a one way trip until exit + if (confirm == 1) + { + opts->audio_in_type = 3; //RTL input, only set this on confirm + //open_rtlsdr_stream(opts); //may move to outside of this box so we return to the normal ncurses term first + choicec = 18; //exit to decoder screen only if confirmed, otherwise, just go back + } + + // if (confirm != 1) + // { + // opts->audio_in_type = 0; + // } + + #endif + + } + + if (choicec == 7) + { + if (opts->dmr_stereo == 0) + { + opts->pulse_digi_rate_out = 48000; + //fprintf (stderr, "Rate Out set to 48kHz\n"); + } + if (opts->dmr_stereo == 1) + { + opts->pulse_digi_rate_out = 24000; + //fprintf (stderr, "Rate Out set to 24kHz\n"); + } + + } + + if (choicec == 8) + { + if (opts->dmr_stereo == 0) + { + opts->pulse_digi_rate_out = 8000; + //fprintf (stderr, "Rate Out set to 8kHz\n"); + } + + if (opts->dmr_stereo == 1) + { + opts->pulse_digi_rate_out = 24000; //always force 24kHz with DMR Stereo + //fprintf (stderr, "Rate Out set to 16kHz\n"); + } + } + + if (choicec == 9) + { + resetState (state); //use sparingly, may cause memory leak + } + + if (choicec == 10) + { + if (opts->ncurses_compact == 0) + { + opts->ncurses_compact = 1; + } + else opts->ncurses_compact = 0; + + } + + if (choicec == 11) + { + if (opts->ncurses_history == 0) + { + opts->ncurses_history = 1; + } + else opts->ncurses_history = 0; + } + + if (choicec == 12) + { + //flesh out all closewavs and sprint "" wav filenames + closeWavOutFile (opts, state); + closeWavOutFileL (opts, state); + closeWavOutFileR (opts, state); + //closeWavOutFileRaw (opts, state); + sprintf (opts->wav_out_file, ""); + sprintf (opts->wav_out_fileR, ""); + opts->dmr_stereo_wav = 0; + } + + if (choicec == 13) //lucky number 13 for OP25 Symbol Capture Bin Files + { + //read in filename for symbol capture bin + entry_win = newwin(6, WIDTH+16, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter OP25 Symbol Capture Bin Filename"); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%s", &opts->audio_in_dev); + noecho(); + //do the thing with the thing + struct stat stat_buf; + if (stat(opts->audio_in_dev, &stat_buf) != 0) + { + fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); + //exit(1); + goto SKIP; + } + if (S_ISREG(stat_buf.st_mode)) + { + opts->symbolfile = fopen(opts->audio_in_dev, "r"); + opts->audio_in_type = 4; //symbol capture bin files + } + SKIP: + choicec = 18; + } + + if (choicec == 14) //replay last file + { + struct stat stat_buf; + if (stat(opts->audio_in_dev, &stat_buf) != 0) + { + fprintf (stderr,"Error, couldn't open %s\n", opts->audio_in_dev); + //exit(1); + goto SKIPR; + } + if (S_ISREG(stat_buf.st_mode)) + { + opts->symbolfile = fopen(opts->audio_in_dev, "r"); + opts->audio_in_type = 4; //symbol capture bin files + } + SKIPR: + choicec = 18; //exit + } + + if (choicec == 15) //stop/close last file PLAYBACK + { + if (opts->symbolfile != NULL) + { + if (opts->audio_in_type == 4) //check first, or issuing a second fclose will crash the SOFTWARE + { + fclose(opts->symbolfile); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once + + } + + } + opts->audio_in_type = 0; //set after closing to prevent above crash condition + + choicec = 18; //exit + } + + if (choicec == 16) //stop/close last file RECORDING + { + if (opts->symbol_out == 1) + { + if (opts->symbol_out_file != NULL) //check first, or issuing a second fclose will crash the SOFTWARE + { + fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once + sprintf (opts->audio_in_dev, opts->symbol_out_file); //swap output bin filename to input for quick replay + } + + opts->symbol_out = 0; //set flag to 1 + + } + choicec = 18; //exit + } + + if (choicec == 17) //RTL UDP Retune + { + //read in new rtl frequency + entry_win = newwin(6, WIDTH+18, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " Enter Frequency in Hz (851.8 MHz is 851800000 Hz) "); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &opts->rtlsdr_center_freq); //ld, or lld? + noecho(); + //do the thing with the thing + data[0] = 0; + data[1] = opts->rtlsdr_center_freq & 0xFF; + data[2] = (opts->rtlsdr_center_freq >> 8) & 0xFF; + data[3] = (opts->rtlsdr_center_freq >> 16) & 0xFF; + data[4] = (opts->rtlsdr_center_freq >> 24) & 0xFF; + + temp_freq = opts->rtlsdr_center_freq; + + choicec = 18; + } + + if (choicec != 0 && choicec != 18 ) //return to last menu + { + //return + choice = 0; + choicec = 0; + //highlightb = 1; + //highlight = 1; + keypad(test_win, FALSE); + keypad(menu_win, TRUE); + delwin(test_win); + print_menu(menu_win, highlight); + //wrefresh(menu_win); + break; + } + if (choicec == 18) //exit both menus + { + //exit + choice = 1; + choicec = 0; + //highlightb = 0; + //highlight = 0; + keypad(test_win, FALSE); + keypad(menu_win, TRUE); + delwin(test_win); + print_menu(menu_win, highlight); + //wrefresh(menu_win); + break; + } + } + clrtoeol(); //clear to end of line? + refresh(); + //endwin(); //causes quick blink in and out of ncursesprinter, not required + } + + //Cheat Code Entry + if (choice == 13) + { + state->payload_keyid = 0; + state->payload_keyidR = 0; + state->K = 0; + + entry_win = newwin(6, WIDTH+6, starty+10, startx+10); + box (entry_win, 0, 0); + mvwprintw(entry_win, 2, 2, " "); + mvwprintw(entry_win, 3, 3, " "); + echo(); + refresh(); + wscanw(entry_win, "%d", &state->K); + noecho(); + opts->dmr_mute_encL = 0; + opts->dmr_mute_encR = 0; + if (state->K > 255) + { + state->K = 255; + } + if (state->K == 0) + { + opts->dmr_mute_encL = 1; + opts->dmr_mute_encR = 1; + } + break; + } + + if (choice == 2) + { + //setup Auto parameters--default ones + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (opts->output_name, "Auto Detect"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 1; + opts->frame_x2tdma = 1; + opts->frame_p25p1 = 1; + opts->frame_nxdn48 = 0; + opts->frame_nxdn96 = 0; + opts->frame_dmr = 1; + opts->frame_dpmr = 0; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + opts->unmute_encrypted_p25 = 0; + break; //break? + + } + if (choice == 3) + { + //ProVoice Specifics + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 5; + state->symbolCenter = 2; + sprintf (opts->output_name, "ProVoice"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + 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 = 1; + opts->mod_c4fm = 0; + opts->mod_qpsk = 0; + opts->mod_gfsk = 1; + state->rf_mod = 2; + break; + } + if (choice == 4) + { + //DSTAR + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (opts->output_name, "D-STAR"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 1; + 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->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + // state->rf_mod = 2; + opts->unmute_encrypted_p25 = 0; + break; + } + if (choice == 5) + { + //P25 P1 + resetState (state); //use sparingly, may cause memory leak + opts->frame_p25p1 = 1; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + state->rf_mod = 0; + sprintf (opts->output_name, "P25P1"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + 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->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + // state->rf_mod = 0; + opts->unmute_encrypted_p25 = 0; + break; + } + + if (choice == 6) + { + //DMR Stereo + resetState (state); //use sparingly, seems to cause issue when switching back to other formats + opts->frame_dmr = 1; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + state->rf_mod = 0; + sprintf (opts->output_name, "DMR STEREO"); + opts->dmr_stereo = 1; //this value is 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; + 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->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + break; + } + if (choice == 7) + { + //set legacy DMR settings + resetState (state); //use sparingly, seems to cause issue when switching back to other formats + opts->frame_dmr = 1; + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + state->rf_mod = 0; + sprintf (opts->output_name, "DMR LEH"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + 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->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + break; + } + if (choice == 8) + { + //dPMR + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 20; + state->symbolCenter = 10; + sprintf (opts->output_name, "dPMR"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + 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 = 1; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + opts->unmute_encrypted_p25 = 0; + break; + } + if (choice == 9) + { + //NXDN48 + resetState (state); //use sparingly, may cause memory leak + opts->frame_nxdn48 = 1; + state->samplesPerSymbol = 20; + state->symbolCenter = 10; + state->rf_mod = 0; + sprintf (opts->output_name, "NXDN48"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 0; + opts->frame_x2tdma = 0; + opts->frame_p25p1 = 0; + opts->frame_nxdn48 = 1; + opts->frame_nxdn96 = 0; + opts->frame_dmr = 0; + opts->frame_dpmr = 0; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->unmute_encrypted_p25 = 0; + // opts->mod_qpsk = 0; + // opts->mod_gfsk = 0; + // state->rf_mod = 0; + } + if (choice == 10) + { + //NXDN96 + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (opts->output_name, "NXDN96"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 0; + opts->frame_x2tdma = 0; + opts->frame_p25p1 = 0; + opts->frame_nxdn48 = 0; + opts->frame_nxdn96 = 1; + opts->frame_dmr = 0; + opts->frame_dpmr = 0; + opts->frame_provoice = 0; + opts->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + opts->unmute_encrypted_p25 = 0; + } + if (choice == 11) + { + //Decode X2-TDMA + //NXDN96 + resetState (state); //use sparingly, may cause memory leak + state->samplesPerSymbol = 10; + state->symbolCenter = 4; + sprintf (opts->output_name, "X2-TDMA"); + opts->dmr_stereo = 0; //this value is the end user option + state->dmr_stereo = 0; //this values toggles on and off depending on voice or data handling + opts->pulse_digi_rate_out = 8000; + opts->pulse_digi_out_channels = 1; + opts->frame_dstar = 0; + opts->frame_x2tdma = 1; + 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->mod_c4fm = 1; + opts->mod_qpsk = 0; + opts->mod_gfsk = 0; + state->rf_mod = 0; + opts->unmute_encrypted_p25 = 0; + } + if (choice == 12) + { + //Set all signal for inversion or uninversion + if (opts->inverted_dmr == 0) + { + opts->inverted_dmr = 1; + opts->inverted_dpmr = 1; + opts->inverted_x2tdma = 1; + opts->inverted_ysf = 1; + } + else + { + opts->inverted_dmr = 0; + opts->inverted_dpmr = 0; + opts->inverted_x2tdma = 0; + opts->inverted_ysf = 0; + } + + } + if (choice == 14) //reset call history (usually if janky output when switching modes) + { + for (short int k = 0; k < 9; k++) + { + call_matrix[k][0] = 0; + call_matrix[k][1] = 0; + call_matrix[k][2] = 0; + call_matrix[k][3] = 0; + call_matrix[k][4] = 0; + call_matrix[k][5] = 0; + } + } + + if (choice == 15) //turn on payload printing + { + opts->payload = 1; + fprintf(stderr, "Payload on\n"); + } + if (choice == 16) //turn off payload printing + { + opts->payload = 0; + fprintf(stderr, "Payload Off\n"); + } + if (choice == 18) + { + opts->lrrp_file_output = 1; + fprintf(stderr, "LRRP to text\n"); + } + if (choice == 19) + { + ncursesClose(); + //cleanup_rtlsdr_stream(); + cleanupAndExit (opts, state); + } + + if(choice != 0 && choice != 20) /* User did a choice come out of the infinite loop */ + break; + + } + + clrtoeol(); //clear to end of line? + refresh(); + state->menuopen = 0; //flag the menu is closed, resume processing getFrameSync + + //reopen pulse output with new parameters + openPulseOutput (opts); + + if (opts->audio_in_type == 0) //reopen pulse input if it is the specified input method + { + openPulseInput(opts); + } + #ifdef USE_RTLSDR + if (opts->audio_in_type == 3) //open rtl input if it is the specified input method + { + ncursesPrinter (opts, state); //run one rep to clear menu boxes out + if (opts->rtl_started == 0) + { + opts->rtl_started = 1; //set here so ncurses terminal doesn't attempt to open it again + open_rtlsdr_stream(opts); + } + + } + #endif + + +} +//end Ncurses Menu + void ncursesPrinter (dsd_opts * opts, dsd_state * state) { - int level; - level = 0; //start each cycle with 0 + int level = 0; + int c = 0; + + if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN - + { + timeout(0); + c = getch(); + } + + //testing sending UDP commands to the socket inside of rtl_sdr_fm.cpp + //this works, but we will want to make an init func open one time, and have sendto here + #ifdef USE_RTLSDR + if (temp_freq == opts->rtlsdr_center_freq) + { + handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + memset((char * ) & address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(SRV_IP); //address of host + address.sin_port = htons(udp_port); + sendto(handle, data, UDP_BUFLEN, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in)); + + temp_freq = -1; + } + #endif //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_keyidR = 0; - state->payload_algidR = 0; - //state->payload_mfid = 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, " "); } @@ -243,7 +1294,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) rdR = state->lastsrcR; } //move to seperate P25 version plz - opts->p25enc = 0; + //opts->p25enc = 0; } //DMR TG @@ -252,13 +1303,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) 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; + //opts->p25enc = 0; + } //P25 @@ -362,6 +1416,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[9][4] = dcc; call_matrix[9][5] = time(NULL); + //open wav file if enabled and both rd and tg are not 0 + if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0) + { + //close old first, assign name based on time and radio, open wav file + closeWavOutFileL (opts, state); + sprintf (opts->wav_out_file, "%s MS - CC %d - TG %d - RD %d.wav", getTimeN(), dcc, tg, rd); + openWavOutFileL (opts, state); //testing for now, will want to move to per call later + } + } //DMR BS Slot 1 - matrix 0-4 @@ -385,6 +1448,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[4][4] = dcc; call_matrix[4][5] = time(NULL); + //open wav file if enabled and both rd and tg are not 0 + if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0) + { + //close old first, assign name based on time and radio, open wav file + closeWavOutFileL (opts, state); + + sprintf (opts->wav_out_file, "%s S1 - CC %d - TG %d - RD %d.wav", getTimeN(), dcc, tg, rd); + openWavOutFileL (opts, state); //testing for now, will want to move to per call later + } + } //DMR BS Slot 2 - matrix 5-9 @@ -408,6 +1481,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) call_matrix[9][4] = dcc; call_matrix[9][5] = time(NULL); + //open wav file if enabled and both rdR and tgR are not 0 + if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0) + { + //close old first, assign name based on time and radio, open wav file + closeWavOutFileR (opts, state); + sprintf (opts->wav_out_fileR, "%s S2 - CC %d - TG %d - RD %d.wav", getTimeN(), dcc, tgR, rdR); + openWavOutFileR (opts, state); //testing for now, will want to move to per call later + } + } //P25 @@ -434,29 +1516,41 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //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 + if (opts->ncurses_compact == 1) { - printw("%s \n", FM_bannerN[i]); + printw ("------------------------------------------------------------------------------\n"); + printw ("| Digital Speech Decoder: Florida Man Edition %s \n", GIT_TAG); } - 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)); + if (opts->ncurses_compact == 0) + { + attron(COLOR_PAIR(6)); //6 + for (short int i = 0; i < 7; i++) + { + printw("%s \n", FM_bannerN[i]); + } + attroff(COLOR_PAIR(6)); //6 + printw ("--Build Info------------------------------------------------------------------\n"); + printw ("| https://github.com/lwvmobile/dsd-fme/tree/pulseaudio\n"); //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 ("------------------------------------------------------------------------------\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: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_in/1000, opts->pulse_digi_in_channels); + } + if (opts->audio_in_type == 4) + { + printw ("| Symbol Capture Input: %s \n", opts->audio_in_dev); } if (opts->audio_in_type == 1) { - printw ("| STDIN Standard Input: - \n"); + printw ("| STDIN Standard Input: - Menu Disabled when using STDIN!\n"); + // printw ("| NCURSES Menu Disabled when using STDIN! - Use CTRL + C to Close. \n"); } if (opts->audio_in_type == 3) { @@ -469,7 +1563,7 @@ 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: [%2i] kHz [%i] Channel\n", opts->pulse_digi_rate_out/1000, opts->pulse_digi_out_channels); } if (opts->monitor_input_audio == 1) { @@ -479,15 +1573,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { printw ("| Writing MBE data files to directory %s\n", opts->mbe_out_dir); } + if (opts->wav_out_file_raw[0] != 0 && opts->audio_in_type == 0) + { + printw ("| Appending Raw Sig Audio WAV to file %s\n", opts->wav_out_file_raw); + } + if (opts->symbol_out_file[0] != 0 && opts->symbol_out == 1) + { + printw ("| Writing Symbol Capture to Bin File: %s\n", opts->symbol_out_file); + } if (opts->wav_out_file[0] != 0 && opts->dmr_stereo == 0) { - printw ("| Appending Audio WAV to file %s\n", opts->wav_out_file); + printw ("| Writing Decoded Audio to WAV File: %s\n", opts->wav_out_file); } + if (opts->dmr_stereo_wav == 1) //opts->wav_out_file[0] != 0 && + { + printw ("| Per Call WAV S1 - %s\n", opts->wav_out_file); + printw ("| Per Call WAV S2 - %s\n", opts->wav_out_fileR); + } + printw ("------------------------------------------------------------------------------\n"); attroff(COLOR_PAIR(4)); - if (state->carrier == 1){ //figure out method that will tell me when is active and when not active, maybe carrier but this doesn't print anyways unless activity + if (state->carrier == 1) + { attron(COLOR_PAIR(3)); level = (int) state->max / 164; //only update on carrier present reset = 1; @@ -540,7 +1649,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) { printw ("| RAN: [%2d] ", rn); printw ("TID: [%4d] ", tgn); - printw ("RID: [%4d] \n| ALG: [0x%02X] KEY [0x%02X] ", src, state->nxdn_cipher_type, state->nxdn_key); + 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); @@ -548,21 +1657,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (state->nxdn_cipher_type == 0x1 && state->carrier == 1) { attron(COLOR_PAIR(2)); - printw ("Scrambler Encryption "); + printw ("Scrambler "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } if (state->nxdn_cipher_type == 0x2 && state->carrier == 1) { attron(COLOR_PAIR(2)); - printw ("DES Encryption "); + printw ("DES-OFB "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } if (state->nxdn_cipher_type == 0x3 && state->carrier == 1) { attron(COLOR_PAIR(2)); - printw ("AES Encryption "); + printw ("AES-256 "); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } @@ -573,24 +1682,38 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } - //printw("%s ", state->nxdn_call_type); printw("\n"); } //P25 if (lls == 0 || lls == 1) { - printw("| TID:[%8i] RID:[%8i] ", tg, rd); + // printw("| TID:[%8i] RID:[%8i] ", tg, rd); + printw("| TID:[%8i] RID:[%8i] ", state->lasttg, state->lastsrc); + printw(" MFID:[0x%02X] ", state->payload_mfid); 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 - if (state->payload_algid != 0x80 && state->payload_algid != 0x0 && state->carrier == 1) + printw(" KID:[0x%04X] ", state->payload_keyid); + printw(" MI:[0x%016llX] ", state->payload_miP); + + if (state->payload_algid != 0x80 && state->payload_algid != 0x0 && state->carrier == 1 && state->R == 0) { attron(COLOR_PAIR(2)); printw("**ENC**"); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); + if (state->payload_algid == 0xAA) + { + attron(COLOR_PAIR(1)); + printw(" ADP/RC4"); + attron(COLOR_PAIR(3)); + } + if (state->payload_algid == 0x81) + { + attron(COLOR_PAIR(1)); + printw(" DES-OFB"); + attron(COLOR_PAIR(3)); + } } printw("\n"); } @@ -627,7 +1750,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) //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? & 0xCF currently + if(state->dmrburstL == 16 && state->payload_algid == 0 && (state->dmr_so & 0xCF) == 0x40) //4F or CF mask? & 0xCF currently { attron(COLOR_PAIR(5)); printw (" **BP** "); @@ -635,15 +1758,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } //Point - if(state->dmrburstL == 16 && state->payload_mi == 0 && state->K > 0 && (state->dmr_so & 0xCF) == 0x40) + if(state->dmrburstL == 16 && state->payload_algid == 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) + //ALG, KeyID, MI //was key_id + if(state->dmrburstL == 16 && state->payload_algid > 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); @@ -651,7 +1774,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } - if(state->dmrburstL == 16 && state->dmr_so == 0x40) //0100 0000 + if(state->dmrburstL == 16 && state->dmr_so == 0x40 && state->R == 0) //0100 0000 { attron(COLOR_PAIR(2)); printw (" **ENC** "); @@ -728,7 +1851,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) 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? + if(state->dmrburstR == 16 && state->payload_algidR == 0 && (state->dmr_soR & 0xCF) == 0x40) //4F or CF mask? { attron(COLOR_PAIR(5)); printw (" **BP** "); @@ -736,15 +1859,15 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } //Point 2 - if(state->dmrburstR == 16 && state->payload_miR == 0 && state->K > 0 && (state->dmr_soR & 0xCF) == 0x40) + if(state->dmrburstR == 16 && state->payload_algidR == 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) + //ALG, KeyID, MI 2 //was keyidR + if(state->dmrburstR == 16 && state->payload_algidR > 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); @@ -752,7 +1875,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attron(COLOR_PAIR(3)); } //Call Types, may switch to the more robust version later? - if(state->dmrburstR == 16 && state->dmr_soR == 0x40) //0100 0000 + if(state->dmrburstR == 16 && state->dmr_soR == 0x40 && state->R == 0) //0100 0000 { attron(COLOR_PAIR(2)); printw (" **ENC** "); @@ -829,65 +1952,72 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if (state->carrier == 1){ //same as above attroff(COLOR_PAIR(3)); } - - attron(COLOR_PAIR(4)); //cyan for history - printw ("--Call History----------------------------------------------------------------\n"); - for (short int j = 0; j < 10; j++) + //only print call history if enabled + if (opts->ncurses_history == 1) { - //only print if a valid time was assinged to the matrix - if ( ((time(NULL) - call_matrix[9-j][5]) < 9999) ) + attron(COLOR_PAIR(4)); //cyan for history + printw ("--Call History----------------------------------------------------------------\n"); + for (short int j = 0; j < 10; j++) { - printw ("| %s ", SyncTypes[call_matrix[9-j][0]]); - if (lls == 8 || lls == 9 || lls == 16 || lls == 17) + //only print if a valid time was assinged to the matrix + if ( ((time(NULL) - call_matrix[9-j][5]) < 9999) ) { - printw ("RAN [%2lld] ", call_matrix[9-j][1]); - printw ("TG [%4lld] ", call_matrix[9-j][4]); - printw ("RID [%4lld] ", call_matrix[9-j][2]); + 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]); } - //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 - + } //end Call History + //fence bottom + printw ("------------------------------------------------------------------------------\n"); + attroff(COLOR_PAIR(4)); //cyan for history + } refresh(); + if (c == 27) //esc key + { + ncursesMenu (opts, state); //just a quick test + } + } //end ncursesPrinter void ncursesClose () { endwin(); - printf("Press CTRL+C again to close. Thanks.\n"); - printf("Run 'reset' in your terminal to clean up if necessary."); + //printf("Press CTRL+C again to close. Thanks.\n"); + //printf("Run 'reset' in your terminal to clean up if necessary.\n"); } diff --git a/src/dsd_reset.c b/src/dsd_reset.c index ab6165d..c34f4a2 100644 --- a/src/dsd_reset.c +++ b/src/dsd_reset.c @@ -8,9 +8,9 @@ resetState (dsd_state * state) int i, j; - state->dibit_buf = malloc (sizeof (int) * 1000000); - state->dibit_buf_p = state->dibit_buf + 200; - memset (state->dibit_buf, 0, sizeof (int) * 200); + // state->dibit_buf = malloc (sizeof (int) * 1000000); + // state->dibit_buf_p = state->dibit_buf + 200; + // memset (state->dibit_buf, 0, sizeof (int) * 200); state->repeat = 0; //not sure yet //state->audio_out_buf = malloc (sizeof (short) * 1000000); //memset (state->audio_out_buf, 0, 100 * sizeof (short)); @@ -95,6 +95,10 @@ resetState (dsd_state * state) state->debug_header_critical_errors = 0; state->nxdn_last_ran = 0; + // state->payload_algid = 0; + // state->payload_algidR = 0; + state->dmr_encL = 0; + state->dmr_encR = 0; //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 diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 2af17e0..39016ba 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -26,6 +26,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) sum = 0; count = 0; + sample = 0; //init sample with a value of 0...see if this was causing issues with raw audio monitoring for (i = 0; i < state->samplesPerSymbol; i++) //right HERE { @@ -81,15 +82,22 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } // Read the new sample from the input - if(opts->audio_in_type == 0) + if(opts->audio_in_type == 0) // && state->menuopen == 0 still not quite working { pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); //look into how processAudio handles playback, not sure if latency issues, or garbage sample values crash pulse when written - if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767) + // if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767) + if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample != 0) { state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here? pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL); } + //playback is wrong, depends on samples_per_symbol, maybe make a buffer and store first? + //making buffer might also fix raw audio monitoring as well + if (opts->wav_out_file_raw[0] != 0) //if set for recording sample raw files + { + //writeRawSample (opts, state, sample); + } } else if (opts->audio_in_type == 1) { @@ -122,7 +130,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) { #ifdef USE_RTLSDR // TODO: need to read demodulated stream here - get_rtlsdr_sample(&sample); + // get_rtlsdr_sample(&sample); + get_rtlsdr_sample(&sample, opts, state); if (opts->monitor_input_audio == 1 && state->lastsynctype == -1 && sample < 32767 && sample > -32767) { state->pulse_raw_out_buffer = sample; //steal raw out buffer sample here? @@ -131,6 +140,11 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) #endif } + // //test reading symbol bin files + // else if (opts->audio_in_type == 4) + // { + // //use fopen and read in a sample, check boatbod op25 for clues + // } #ifdef TRACE_DSD state->debug_sample_index++; @@ -338,6 +352,73 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } #endif + //read op25/fme symbol bin files + if (opts->audio_in_type == 4) + { + //use fopen and read in a symbol, check op25 for clues + if(opts->symbolfile == NULL) + { + fprintf(stderr, "Error Opening File %s\n", opts->symbolfile); + return(-1); + } + + state->symbolc = fgetc(opts->symbolfile); + //fprintf(stderr, "%d", state->symbolc); + if( feof(opts->symbolfile) ) + { + opts->audio_in_type = 0; //switch to pulse after playback, ncurses terminal can initiate replay if wanted + fclose(opts->symbolfile); + openPulseInput(opts); + } + + //flipping these to 'positive' produces terrible results in P25 P1, and I tried flopping it every way I could + //positive polarity works fine with DMR, but not P25, so may look at reading and storing based on frame type? + if (opts->frame_p25p1 == 1) //use inverted polarity for reading P25, but not DMR (or others?) + { + if (state->symbolc == 0) + { + symbol = -1; //-1 + } + if (state->symbolc == 1) + { + symbol = -3; //-3 + } + if (state->symbolc == 2) + { + symbol = 1; //1 + } + if (state->symbolc == 3) + { + symbol = 3; //3 + } + } + else if (opts->frame_provoice == 1) //syncs fine, but issues with dibit reading + { + //provoice has issue where sync is okay, but decode isn't working after sync + //symbol = state->symbolc; + } + else + { + if (state->symbolc == 0) + { + symbol = 1; //-1 + } + if (state->symbolc == 1) + { + symbol = 3; //-3 + } + if (state->symbolc == 2) + { + symbol = -1; //1 + } + if (state->symbolc == 3) + { + symbol = -3; //3 + } + } + + } + state->symbolcnt++; return (symbol); diff --git a/src/fec.c b/src/fec.c index 6180f2d..cfb95f5 100644 --- a/src/fec.c +++ b/src/fec.c @@ -1224,10 +1224,11 @@ void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits) encodedBits[j] += origBits[i] * Golay_24_12_m_G[24*i + j]; } } - + // fprintf (stderr, "\n Inside Golay - Encoded Bits = "); //disable later on for (i = 0; i < 24; i++) { encodedBits[i] %= 2; + // fprintf (stderr, "%b", encodedBits[i]); //disable later on } } diff --git a/src/nxdn_data.c b/src/nxdn_data.c index 3dc93e2..87d2bf3 100644 --- a/src/nxdn_data.c +++ b/src/nxdn_data.c @@ -1,9 +1,6 @@ #include "dsd.h" #include "nxdn_const.h" -//don't know why this doesn't work right in LEH, need to figure that out for him -//works just fien when ripped from his and into mine -//must be some random thing, I'll look at his when I have a chance void processNXDNData (dsd_opts * opts, dsd_state * state) { int i, dibit = 0; @@ -24,7 +21,7 @@ void processNXDNData (dsd_opts * opts, dsd_state * state) } /* Start pseudo-random NXDN sequence after - * LITCH = 16 bit = 8 dibit + * LICH = 16 bit = 8 dibit * ==> Index 8 */ pr = (unsigned char *)(&nxdnpr2[8]); for (i = 0; i < 30; i++) diff --git a/src/nxdn_lib.c b/src/nxdn_lib.c index 22c8c75..5b3fea1 100644 --- a/src/nxdn_lib.c +++ b/src/nxdn_lib.c @@ -60,13 +60,13 @@ } /* End ConvertBitIntoBytes() */ -uint8_t NXDN_decode_LICH(uint8_t InputLich[8], - uint8_t * RFChannelType, - uint8_t * FunctionnalChannelType, - uint8_t * Option, - uint8_t * Direction, - uint8_t * CompleteLichBinaryFormat, - uint8_t Inverted) + uint8_t NXDN_decode_LICH(uint8_t InputLich[8], + uint8_t * RFChannelType, + uint8_t * FunctionnalChannelType, + uint8_t * Option, + uint8_t * Direction, + uint8_t * CompleteLichBinaryFormat, + uint8_t Inverted) { uint8_t GoodParity = 0; uint32_t i; @@ -294,6 +294,7 @@ void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state) /* Check CRC */ if(state->NxdnSacchRawPart[i].CrcIsGood == 0) CrcCorrect = 0; + //fprintf(stderr, "\n SAACH P# %1d - %05X", i, state->NxdnSacchRawPart[i].Data); } /* Decodes the element content */ @@ -553,7 +554,7 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state, uint32_t i; uint8_t MessageType; uint64_t CurrentIV = 0; - + unsigned long long int FullMessage = 0; /* Get the "Message Type" field */ MessageType = (ElementsContent[2] & 1) << 5; MessageType |= (ElementsContent[3] & 1) << 4; @@ -562,6 +563,8 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state, MessageType |= (ElementsContent[6] & 1) << 1; MessageType |= (ElementsContent[7] & 1) << 0; + //fprintf(stderr, "\nMessage Type = %X ", MessageType); + /* Save the "F1" and "F2" flags */ state->NxdnElementsContent.F1 = ElementsContent[0]; state->NxdnElementsContent.F2 = ElementsContent[1]; @@ -569,7 +572,16 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state, /* Save the "Message Type" field */ state->NxdnElementsContent.MessageType = MessageType; - //fprintf(stderr, "Message Type = 0x%02X ", MessageType & 0xFF); + //fprintf(stderr, "\n Message Type = 0x%02X ", MessageType & 0xFF); + + //Dump the Message into a HEX value for vieweing + //FullMessage = (unsigned long long int)ConvertBitIntoBytes(&Message[0], 64); + for (short int i = 0; i < 64; i++) + { + FullMessage = FullMessage << 1; + FullMessage |= ElementsContent[i]; + } + //fprintf(stderr, "\nFull Message = %016llX ", FullMessage); /* Decode the right "Message Type" */ switch(MessageType) @@ -666,6 +678,7 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) uint8_t KeyID = 0; uint8_t DuplexMode[32] = {0}; uint8_t TransmissionMode[32] = {0}; + unsigned long long int FullMessage = 0; //UNUSED_VARIABLE(opts); //UNUSED_VARIABLE(state); @@ -712,14 +725,14 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) if(CCOption & 0x40) fprintf(stderr, "Visitor "); if(CCOption & 0x20) fprintf(stderr, "Priority Paging "); - /* On an AES or DES encrypted frame one IV is used on two - * superframe. - * The first superframe contains a VCALL message inside - * the SACCH and the second superframe contains the next IV - * to use. - * - * Set the correct part of encrypted frame flag. - */ + //Dump the Message into a HEX value for vieweing + //FullMessage = (unsigned long long int)ConvertBitIntoBytes(&Message[0], 64); + // for (short int i = 0; i < 64; i++) + // { + // FullMessage = FullMessage << 1; + // FullMessage |= Message[i]; + // } + if((CipherType == 2) || (CipherType == 3)) { state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1; @@ -742,11 +755,17 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode); fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode); + /* Print Source ID and Destination ID (Talk Group or Unit ID) */ + //fprintf (stderr, "%s", KGRN); + fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF); + fprintf (stderr, "%s", KNRM); + //state->nxdn_key = (KeyID & 0xFF); //state->nxdn_cipher_type = CipherType; /* Print the "Cipher Type" */ if(CipherType != 0) { + fprintf (stderr, "\n %s", KYEL); fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType)); //state->nxdn_cipher_type = CipherType; } @@ -754,18 +773,12 @@ 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); + //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) { if ( (SourceUnitID & 0xFFFF) > 0 ) @@ -773,10 +786,19 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay state->nxdn_last_tg = (DestinationID & 0xFFFF); state->nxdn_key = (KeyID & 0xFF); - state->nxdn_cipher_type = CipherType; + state->nxdn_cipher_type = CipherType; //will this set to zero if no enc? } //fprintf(stderr, "(CRC OK) "); } + //set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic + if (state->nxdn_cipher_type != 0) + { + state->dmr_encL = 1; + } + if (state->nxdn_cipher_type == 0) + { + state->dmr_encL = 0; + } //fprintf(stderr, " (OK) - "); else { @@ -784,7 +806,7 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) fprintf(stderr, "(CRC ERR) "); fprintf (stderr, "%s", KNRM); } - + //fprintf(stderr, "\nFull Message = %016llX ", FullMessage); } /* End NXDN_decode_VCALL() */ @@ -815,21 +837,15 @@ void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message) * * Message[8..71] contains : The 64 bits IV */ - + state->payload_miN = 0; //zero out /* Extract the IV from the VCALL_IV message */ for(i = 0; i < 8; i++) { state->NxdnElementsContent.IV[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i + 1) * 8], 8); + + state->payload_miN = state->payload_miN << 8 | state->NxdnElementsContent.IV[i]; } - /* On an AES or DES encrypted frame one IV is used on two - * superframe. - * The first superframe contains a VCALL message inside - * the SACCH and the second superframe contains the next IV - * to use. - * - * Set the correct part of encrypted frame flag. - */ state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 2; state->NxdnElementsContent.PartOfNextEncryptedFrame = 1; @@ -1012,35 +1028,640 @@ uint8_t CRC6BitNXDN(uint8_t * BufferIn, uint32_t BitLength) return CRC; } /* End CRC6BitNXDN() */ - -/* Scrambler used for NXDN transmission (different of the - * voice encryption scrambler), see NXDN Part1-A Common Air Interface chapter - * 4.6 for the polynomial description. - * It is a X^9 + X^4 + 1 polynomial used as pseudo-random generator */ -void ScrambledNXDNVoiceBit(int * LfsrValue, char * BufferIn, char * BufferOut, int NbOfBitToScramble) +//NXDN IDLE +void ProcessNXDNIdleData (dsd_opts * opts, dsd_state * state, uint8_t Inverted) { - uint32_t i; - uint32_t LFSR; - uint8_t bit; + int i, dibit = 0; + unsigned char sacch_raw[72] = {0}; + unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */ + unsigned char *pr; + uint8_t CrcIsGood = 0; + uint8_t StructureField = 0; + uint8_t RAN = 0; + uint8_t PartOfFrame = 0; - /* Load the initial LFSR value - * LFSR = 0x0E4 at starting value */ - LFSR = (uint32_t)*LfsrValue; - - for(i = 0; i < (uint32_t)NbOfBitToScramble; i++) + if (opts->errorbars == 1) { - /* Bit 0 of LFSR is used to scramble data */ - BufferOut[i] = (BufferIn[i] ^ (LFSR & 1)) & 1; - - /* Compute bit = X^0 + X^4 */ - bit = ((LFSR & 1) ^ ((LFSR >> 4) & 1)) & 1; - - /* Insert bit on the 9th bit (X^9) */ - LFSR = ((LFSR >> 1) & 0xFF) | ((bit << 8) & 0x100); + fprintf(stderr, "DATA - "); } - *LfsrValue = (int)LFSR; -} /* End ScrambledNXDNVoiceBit() */ + /* Start pseudo-random NXDN sequence after + * LICH = 16 bit = 8 dibit + * ==> Index 8 */ + pr = (unsigned char *)(&nxdnpr[8]); + for (i = 0; i < 30; i++) + { + dibit = getDibit (opts, state); + + /* Store and de-interleave directly SACCH bits */ + sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 + sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 + pr++; +#ifdef NXDN_DUMP + fprintf(stderr, "%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + fprintf(stderr, " "); +#endif + + + /* Decode the SACCH fields */ + CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); + StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ + RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ + + /* Compute the Part of Frame according to the structure field */ + if (StructureField == 3) PartOfFrame = 0; + else if(StructureField == 2) PartOfFrame = 1; + else if(StructureField == 1) PartOfFrame = 2; + else if(StructureField == 0) PartOfFrame = 3; + else PartOfFrame = 0; /* Normally we should never go here */ + + /* Fill the SACCH structure */ + state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; + state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; + state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; + memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ + + fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); + if(CrcIsGood) fprintf(stderr, " (OK) - "); + else fprintf(stderr, "(CRC ERR) - "); + + + /* This frame is an idle frame */ + fprintf(stderr, "Idle"); + + + /* Decode the SACCH only when all 4 voice frame + * SACCH spare parts have been received */ + if(PartOfFrame == 3) + { + /* Decode the entire SACCH content */ + NXDN_SACCH_Full_decode(opts, state); + } + + for (i = 0; i < 144; i++) + { + dibit = getDibit (opts, state); +#ifdef NXDN_DUMP + fprintf(stderr, "%c", dibit + 48); +#endif + } + + if (opts->errorbars == 1) + { + fprintf(stderr, "\n"); + } + + /* Reset the SACCH CRCs when all 4 voice frame + * SACCH spare parts have been received */ + if(PartOfFrame == 3) + { + /* Reset all CRCs of the SACCH */ + for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; + } +} /* End ProcessNXDNIdleData() */ + +void ProcessNXDNFacch1Data (dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + int i, j, dibit = 0; + unsigned char sacch_raw[72] = {0}; + unsigned char sacch_decoded[32] = {0}; /* 26 bits + 6 bits CRC */ + unsigned char facch1_raw[144] = {0}; + unsigned char facch1_decoded[96] = {0}; /* 80 bits + 12 bits CRC + 4 bits "Tail" (set to "0") */ + unsigned char *pr; + uint8_t CrcIsGood = 0; + uint8_t StructureField = 0; + uint8_t RAN = 0; + uint8_t PartOfFrame = 0; + uint8_t Facch1CrcIsGood = 0; + + if (opts->errorbars == 1) + { + fprintf(stderr, "DATA - "); + } + + /* Start pseudo-random NXDN sequence after + * LITCH = 16 bit = 8 dibit + * ==> Index 8 */ + pr = (unsigned char *)(&nxdnpr[8]); + for (i = 0; i < 30; i++) + { + dibit = getDibit (opts, state); + + /* Store and de-interleave directly SACCH bits */ + sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 + sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 + pr++; +#ifdef NXDN_DUMP + fprintf(stderr, "%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + fprintf(stderr, " "); +#endif + + + /* Decode the SACCH fields */ + CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); + StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ + RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ + + /* Compute the Part of Frame according to the structure field */ + if (StructureField == 3) PartOfFrame = 0; + else if(StructureField == 2) PartOfFrame = 1; + else if(StructureField == 1) PartOfFrame = 2; + else if(StructureField == 0) PartOfFrame = 3; + else PartOfFrame = 0; /* Normally we should never go here */ + + /* Fill the SACCH structure */ + state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; + state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; + state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; + memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ + + fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); + if(CrcIsGood) fprintf(stderr, " (OK) - "); + else fprintf(stderr, "(CRC ERR) - "); + + + /* This frame is an FACCH1 frame */ + fprintf(stderr, "FACCH1 - "); + + + /* Decode the SACCH only when all 4 voice frame + * SACCH spare parts have been received */ + if(PartOfFrame == 3) + { + /* Decode the entire SACCH content */ + //NXDN_SACCH_Full_decode(opts, state); + } + + /* Start pseudo-random NXDN sequence after + * LITCH = 16 bit = 8 dibit + + * SACCH = 60 bit = 30 dibit + * = 76 bit = 38 dibit + * ==> Index 38 */ + pr = (unsigned char *)(&nxdnpr[38]); + + /* The frame contains 2 * 144 bits = 2 * 72 dibit */ + for(j = 0; j < 2; j++) + { + for (i = 0; i < 72; i++) + { + dibit = getDibit (opts, state); + + /* Store and FACCH1 bits */ + facch1_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 + facch1_raw[(2*i)+1] = (1 & dibit); // bit 0 + pr++; + +#ifdef NXDN_DUMP + fprintf(stderr, "%c", dibit + 48); +#endif + } /* End for (i = 0; i < 72; i++) */ + + /* Extract the FACCH1 content */ + Facch1CrcIsGood = NXDN_FACCH1_decode(facch1_raw, facch1_decoded); + + state->NxdnFacch1RawPart[j].CrcIsGood = Facch1CrcIsGood; + memcpy(state->NxdnFacch1RawPart[j].Data, facch1_decoded, 80); + + if(Facch1CrcIsGood) fprintf(stderr, "FACCH1 CRC %d is good - ", j + 1); + else fprintf(stderr, "FACCH1 CRC %d is bad - ", j + 1); + } /* End for(j = 0; j < 2; j++) */ + + if (opts->errorbars == 1) + { + fprintf(stderr, "\n"); + } + + /* Reset the SACCH CRCs when all 4 voice frame + * SACCH spare parts have been received */ + if(PartOfFrame == 3) + { + /* Reset all CRCs of the SACCH */ + for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; + } +} /* End ProcessNXDNFacch1Data() */ + +void ProcessNXDNUdchData (dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + int i, dibit = 0; + unsigned char facch2_raw[348] = {0}; + unsigned char facch2_decoded[203] = {0}; /* 184 bits + 15 bits CRC + 4 bits "Tail" (set to "0") */ + unsigned char *pr; + uint8_t Facch2CrcIsGood = 0; + uint8_t StructureField = 0; + uint8_t RAN = 0; + + if (opts->errorbars == 1) + { + fprintf(stderr, "DATA - "); + } + + /* Start pseudo-random NXDN sequence after + * LITCH = 16 bit = 8 dibit + * ==> Index 8 */ + pr = (unsigned char *)(&nxdnpr[8]); + for (i = 0; i < 174; i++) + { + dibit = getDibit (opts, state); + + /* Store and de-interleave directly SACCH bits */ + facch2_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 + facch2_raw[(2*i)+1] = (1 & dibit); // bit 0 + pr++; +#ifdef NXDN_DUMP + fprintf(stderr, "%c", dibit + 48); +#endif + } +#ifdef NXDN_DUMP + fprintf(stderr, " "); +#endif + + /* Extract the UDCH/FACCH2 content */ + Facch2CrcIsGood = NXDN_UDCH_decode(facch2_raw, facch2_decoded); + + state->NxdnFacch2RawPart.CrcIsGood = Facch2CrcIsGood; + memcpy(state->NxdnFacch2RawPart.Data, facch2_decoded, 184); + + StructureField = (facch2_decoded[0]<<1 | facch2_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the FACCH2) */ + RAN = (facch2_decoded[2]<<5 | facch2_decoded[3]<<4 | facch2_decoded[4]<<3 | facch2_decoded[5]<<2 | facch2_decoded[6]<<1 | facch2_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the FACCH2) */ + + fprintf(stderr, "RAN=%02d ", RAN); + if(Facch2CrcIsGood) fprintf(stderr, " (OK) - "); + else fprintf(stderr, "(CRC ERR) - "); + + /* This frame is an FACCH2 frame */ + fprintf(stderr, "FACCH2 - "); + + if(Facch2CrcIsGood) fprintf(stderr, "UDCH/FACCH2 CRC is good - "); + else fprintf(stderr, "UDCH/FACCH2 CRC is bad - "); + + if (opts->errorbars == 1) + { + fprintf(stderr, "\n"); + } +} /* End ProcessNXDNUdchData() */ + +void ProcessNXDNFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + /* Switch to the correct type of frame */ + switch(state->NxdnLich.RFChannelType) + { + /* RCCH */ + case 0: + { + ProcessNxdnRCCHFrame(opts, state, Inverted); + break; + } /* End case 0 */ + + /* RTCH */ + case 1: + { + ProcessNxdnRTCHFrame(opts, state, Inverted); + break; + } /* End case 1 */ + + /* RDCH */ + case 2: + { + ProcessNxdnRDCHFrame(opts, state, Inverted); + break; + } /* End case 2 */ + + /* RTCH_C (Composite Control Channel) */ + case 3: + { + ProcessNxdnRTCH_C_Frame(opts, state, Inverted); + break; + } /* End case 3 */ + + default: + { + fprintf(stderr, "- Unknown NXDN Frame type\n"); + + /* Unknown frame type, simply skip the entire frame + * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit + * Preserve 24 bits (12 dibit) => 174 - 12 = 162 dibit */ + skipDibit(opts, state, ((384 - 20 - 16) / 2) - 12); + break; + } /* End default */ + } /* End switch(state->NxdnLich.RFChannelType) */ +} /* End NxdnDecodeFrame() */ + +void ProcessNxdnRCCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + uint8_t SkipEntireFrameFlag = 0; + + /* Remove compiler warning */ + // UNUSED_VARIABLE(Inverted); + + sprintf(state->fsubtype, " RCCH "); + + switch(state->NxdnLich.CompleteLich) + { + case 0b0011000: + { + fprintf(stderr, "- RCCH - CCCH Transmission using Short CAC\n"); + SkipEntireFrameFlag = 1; + break; + } + case 0b0001000: + { + fprintf(stderr, "- RCCH - UPCH or CCCH Transmission using Long CAC\n"); + SkipEntireFrameFlag = 1; + break; + } + case 0b0000001: + { + fprintf(stderr, "- RCCH - CAC Transmission\n"); + SkipEntireFrameFlag = 1; + break; + } + case 0b0000011: + { + fprintf(stderr, "- RCCH - CAC Transmission which has not to be received\n"); + SkipEntireFrameFlag = 1; + break; + } + case 0b0000101: + { + fprintf(stderr, "- RCCH - CAC Transmission which can be received arbitrary\n"); + SkipEntireFrameFlag = 1; + break; + } + case 0b0011001: + { + fprintf(stderr, "- RCCH - IDAS\n"); + SkipEntireFrameFlag = 1; + break; + } + default: + { + fprintf(stderr, "- RCCH - Unknown RCCH Frame\n"); + SkipEntireFrameFlag = 1; + break; + } /* End default */ + } /* switch(state->NxdnLich.CompleteLich) */ + + if(SkipEntireFrameFlag) + { + /* Unknown frame type or frame not implemented yet, simply skip the entire frame + * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit + * Preserve 24 bits (12 dibit) => 174 - 12 = 162 dibit */ + skipDibit(opts, state, ((384 - 20 - 16) / 2) - 12); + } + +} /* End ProcessNxdnRCCHFrame() */ + +void ProcessNxdnRDCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + uint8_t SkipEntireFrameFlag = 0; + + /* Remove compiler warning */ + // UNUSED_VARIABLE(Inverted); + + switch(state->NxdnLich.CompleteLich) + { + /* Voice frame */ + case 0b1010110: /* Voice call transmission : Superframe SACCH, VCH Only */ + case 0b1010100: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ + case 0b1010010: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ + case 0b1010111: /* Voice call transmission : Superframe SACCH, VCH Only */ + case 0b1010101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ + case 0b1010011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ + { + fprintf(stderr, "- RDCH - "); + processNXDNVoice(opts, state); + break; + } + + case 0b1010000: /* Voice call transmission : Superframe SACCH, two FACCH1s */ + case 0b1010001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ + { + fprintf(stderr, "- RDCH - "); + processNXDNData(opts, state); + break; + } + + case 0b1011000: /* Voice call transmission : Superframe SACCH, Idle State */ + case 0b1011001: /* Voice call transmission : Superframe SACCH, Idle State */ + { + fprintf(stderr, "- RDCH - "); + ProcessNXDNIdleData(opts, state, Inverted); + break; + } + + case 0b1000000: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ + case 0b1000001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ + { + //fprintf(stderr, "- RDCH - Non-superframe SACCH with two FACCH1s\n"); + fprintf(stderr, "- RDCH - "); + ProcessNXDNFacch1Data(opts, state, Inverted); + break; + } + + case 0b1001110: /* UDCH Transmission */ + case 0b1001111: /* UDCH Transmission */ + { + fprintf(stderr, "- RDCH - UDCH Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + + case 0b1001000: /* FACCH2 Transmission */ + case 0b1001001: /* FACCH2 Transmission */ + { + fprintf(stderr, "- RDCH - FACCH2 Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + + default: + { + fprintf(stderr, "- RDCH - Unknown RDCH Frame\n"); + SkipEntireFrameFlag = 1; + break; + } /* End default */ + } /* End switch(state->NxdnLich.CompleteLich) */ + + if(SkipEntireFrameFlag) + { + /* Unknown frame type or frame not implemented yet, simply skip the entire frame + * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit + * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ + skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); + } +} /* End ProcessNxdnRDCHFrame() */ + +void ProcessNxdnRTCH_C_Frame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + uint8_t SkipEntireFrameFlag = 0; + + /* Remove compiler warning */ + // UNUSED_VARIABLE(Inverted); + + switch(state->NxdnLich.CompleteLich) + { + /* Voice frame */ + case 0b1110111: /* Voice call transmission : Superframe SACCH, VCH Only */ + case 0b1110101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ + case 0b1110011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ + { + fprintf(stderr, "- RTCH_C - "); + processNXDNVoice(opts, state); + break; + } + + case 0b1110001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ + { + fprintf(stderr, "- RTCH_C - "); + processNXDNData(opts, state); + break; + } + + case 0b1111001: /* Voice call transmission : Superframe SACCH, Idle State */ + { + fprintf(stderr, "- RTCH_C - "); + ProcessNXDNIdleData(opts, state, Inverted); + break; + } + + case 0b1100001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ + { + //fprintf(stderr, "- RTCH_C - Non-superframe SACCH with two FACCH1s\n"); + fprintf(stderr, "- RTCH_C - "); + ProcessNXDNFacch1Data(opts, state, Inverted); + break; + } + + case 0b1101111: /* UDCH Transmission */ + { + fprintf(stderr, "- RTCH_C - UDCH Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + + case 0b1101001: /* FACCH2 Transmission */ + { + fprintf(stderr, "- RTCH_C - FACCH2 Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + + default: + { + fprintf(stderr, "- RTCH_C - Unknown RTCH_C Frame\n"); + SkipEntireFrameFlag = 1; + break; + } /* End default */ + } /* End switch(state->NxdnLich.CompleteLich) */ + + if(SkipEntireFrameFlag) + { + /* Unknown frame type or frame not implemented yet, simply skip the entire frame + * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit + * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ + skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); + } +} + + + +/* + * @brief : This function decodes an NXDN RTCH frame + * + * @param opts : Options + * + * @param state : State + * + * @param Inverted : 1 = Inverted frame ; 0 = Normal frame + * + * @return None + * + */ +void ProcessNxdnRTCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) +{ + uint8_t SkipEntireFrameFlag = 0; + + /* Remove compiler warning */ + // UNUSED_VARIABLE(Inverted); + + switch(state->NxdnLich.CompleteLich) + { + /* Voice frame */ + case 0b0110110: /* Voice call transmission : Superframe SACCH, VCH Only */ + case 0b0110100: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ + case 0b0110010: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ + case 0b0110111: /* Voice call transmission : Superframe SACCH, VCH Only */ + case 0b0110101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ + case 0b0110011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ + { + fprintf(stderr, "- RTCH - "); + processNXDNVoice(opts, state); + break; + } + + case 0b0110000: /* Voice call transmission : Superframe SACCH, two FACCH1s */ + case 0b0110001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ + { + fprintf(stderr, "- RTCH - "); + processNXDNData(opts, state); + break; + } + + case 0b0111000: /* Voice call transmission : Superframe SACCH, Idle State */ + case 0b0111001: /* Voice call transmission : Superframe SACCH, Idle State */ + { + fprintf(stderr, "- RTCH - "); + ProcessNXDNIdleData(opts, state, Inverted); + break; + } + + case 0b0100000: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ + case 0b0100001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ + { + //fprintf(stderr, "- RTCH - Non-superframe SACCH with two FACCH1s\n"); + fprintf(stderr, "- RDCH - "); + ProcessNXDNFacch1Data(opts, state, Inverted); + break; + } + + case 0b0101110: /* UDCH Transmission */ + case 0b0101111: /* UDCH Transmission */ + { + fprintf(stderr, "- RTCH - UDCH Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + + case 0b0101000: /* FACCH2 Transmission */ + case 0b0101001: /* FACCH2 Transmission */ + { + fprintf(stderr, "- RTCH - FACCH2 Transmission - "); + ProcessNXDNUdchData(opts, state, Inverted); + break; + } + default: + { + fprintf(stderr, "- RTCH - Unknown RTCH Frame\n"); + SkipEntireFrameFlag = 1; + break; + } /* End default */ + } /* End switch(state->NxdnLich.CompleteLich) */ + + if(SkipEntireFrameFlag) + { + /* Unknown frame type or frame not implemented yet, simply skip the entire frame + * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit + * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ + skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); + } +} /* End ProcessNxdnRTCHFrame() */ + diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index 9aa6fb2..ffc454e 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -1,9 +1,6 @@ #include "dsd.h" #include "nxdn_const.h" -//don't know why this doesn't work right in LEH, need to figure that out for him -//works just fien when ripped from his and into mine -//must be some random thing, I'll look at his when I have a chance void processNXDNVoice (dsd_opts * opts, dsd_state * state) { int i, j, dibit; @@ -143,11 +140,12 @@ void processNXDNVoice (dsd_opts * opts, dsd_state * state) y++; z++; } - if (opts->payload == 1 && opts->dmr_stereo == 1) + if (opts->payload == 1) { - fprintf(stderr, "\n"); + //fprintf(stderr, "\n"); } processMbeFrame (opts, state, NULL, ambe_fr, NULL); + state->p25vc++; //increment counter by one here? } /* End for (j = 0; j < 4; j++) */ @@ -162,5 +160,6 @@ void processNXDNVoice (dsd_opts * opts, dsd_state * state) { /* Reset all CRCs of the SACCH */ for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; + } } /* End processNXDNVoice() */ diff --git a/src/p25_p2.c b/src/p25_p2.c new file mode 100644 index 0000000..46dcf23 --- /dev/null +++ b/src/p25_p2.c @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------------- + * p25_p2.c + * Phase 2 TDMA Voice handling + * + * LWVMOBILE + * 2022-08 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" + +void processP2(dsd_opts * opts, dsd_state * state) +{ + //Do Something + fprintf (stderr, " Future Development\n"); //obligatory +} diff --git a/src/p25p1_hdu.c b/src/p25p1_hdu.c index 1bdd2c7..36d0b4f 100644 --- a/src/p25p1_hdu.c +++ b/src/p25p1_hdu.c @@ -467,12 +467,24 @@ processHDU(dsd_opts* opts, dsd_state* state) mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32); mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32); mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8); + //only use 64 MSB, trailing 8 bits aren't used, so no mihex3 + state->payload_miP = (mihex1 << 32) | (mihex2); } - if (1 == 1) //print on payload == 1 + //set vc counter to 0 + state->p25vc = 0; + + if (state->payload_algid != 0x80) //print on payload == 1 { 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, " HDU ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX MFID: 0x%02X", algidhex, kidhex, mihex1, mihex2, mihex3, state->payload_mfid); + fprintf (stderr, "%s", KNRM); + } + + if (state->payload_algid != 0x80) //print on payload == 1 + { + fprintf (stderr, "%s", KRED); + fprintf (stderr, " ENC \n"); fprintf (stderr, "%s", KNRM); } diff --git a/src/p25p1_ldu.c b/src/p25p1_ldu.c index 4c83b38..6e2cecd 100644 --- a/src/p25p1_ldu.c +++ b/src/p25p1_ldu.c @@ -119,8 +119,17 @@ process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count) #ifdef TRACE_DSD state->debug_prefix = '\0'; #endif + //check for enc, then always run below step and mute at the point of playing audio so we can still dump the frames + if (state->payload_algid != 0x80) + { + state->dmr_encL = 1; + } + if (state->payload_algid == 0x80) + { + state->dmr_encL = 0; + } - if (state->p25kid == 0 || opts->unmute_encrypted_p25 == 1) + if (1 == 1) //state->p25kid == 0 || opts->unmute_encrypted_p25 == 1 { { // Check for a non-standard c0 transmitted diff --git a/src/p25p1_ldu1.c b/src/p25p1_ldu1.c index 2c6fe5f..aa73be6 100644 --- a/src/p25p1_ldu1.c +++ b/src/p25p1_ldu1.c @@ -65,7 +65,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '1'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 2 read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -78,7 +77,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '2'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 3 read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -91,7 +89,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '3'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 4 read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -104,7 +101,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '4'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 5 read_and_correct_hex_word (opts, state, &(hex_parity[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -117,7 +113,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '5'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 6 read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -130,7 +125,6 @@ processLDU1 (dsd_opts* opts, dsd_state* state) state->debug_prefix_2 = '6'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 7 read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 3611cb3..d5fe4d2 100644 --- a/src/p25p1_ldu2.c +++ b/src/p25p1_ldu2.c @@ -49,6 +49,8 @@ processLDU2 (dsd_opts * opts, dsd_state * state) // so we start counter at 36-14-1 = 21 status_count = 21; + state->p25vc = 9; + if (opts->errorbars == 1) { //fprintf (stderr, "e:"); @@ -65,7 +67,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '1'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 2 read_and_correct_hex_word (opts, state, &(hex_data[15][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[14][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -78,7 +79,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '2'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 3 read_and_correct_hex_word (opts, state, &(hex_data[11][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[10][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -91,7 +91,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '3'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 4 read_and_correct_hex_word (opts, state, &(hex_data[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -104,7 +103,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '4'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 5 read_and_correct_hex_word (opts, state, &(hex_data[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_data[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -117,7 +115,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '5'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 6 read_and_correct_hex_word (opts, state, &(hex_parity[ 7][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 6][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -130,7 +127,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '6'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 7 read_and_correct_hex_word (opts, state, &(hex_parity[ 3][0]), &status_count, analog_signal_array, &analog_signal_index); read_and_correct_hex_word (opts, state, &(hex_parity[ 2][0]), &status_count, analog_signal_array, &analog_signal_index); @@ -143,7 +139,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state) state->debug_prefix_2 = '7'; #endif process_IMBE (opts, state, &status_count); - // Read data after IMBE 8: LSD (low speed data) { char lsd[8]; @@ -185,6 +180,9 @@ processLDU2 (dsd_opts * opts, dsd_state * state) #endif process_IMBE (opts, state, &status_count); + //set vc counter to 0 + state->p25vc = 0; + if (opts->errorbars == 1) { fprintf (stderr, "\n"); @@ -373,48 +371,23 @@ processLDU2 (dsd_opts * opts, dsd_state * state) mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32); mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32); mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8); - //need to check this for accuracy, may be incorrect, MI may also be incorrect, I have 72, but LFSR shows 64 - state->payload_miP = (mihex1 << 40) | (mihex2 << 8) | mihex3; + //only use 64 MSB, trailing 8 bits aren't used, so no mihex3 + state->payload_miP = (mihex1 << 32) | (mihex2); } - if (1 == 1) //print on payload == 1 + if (state->payload_algid != 0x80) //print on payload == 1 { 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, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08llX%08llX%02llX", algidhex, kidhex, mihex1, mihex2, mihex3); fprintf (stderr, "%s", KNRM); } - if (opts->payload == 1) - { - //LFSRP(state); - } - //why am I doing this part below again? - if (opts->payload == 0) - { - algidhex = strtol (algid, NULL, 2); - kidhex = strtol (kid, NULL, 2); - } -} -//needs some work to make mi value fit in there since its a 72 bit value, need to check this over -//LFSR code courtesy of https://github.com/mattames/LFSR/ -int LFSRP(dsd_state * state) -{ - uint64_t lfsr = 0; - lfsr = state->payload_miP; - uint8_t cnt = 0; - - for(cnt=0;cnt<32;cnt++) + if (state->payload_algid != 0x80) //print on payload == 1 { - // Polynomial is C(x) = x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1 - uint64_t bit = ((lfsr >> 63) ^ (lfsr >> 61) ^ (lfsr >> 45) ^ (lfsr >> 37) ^ (lfsr >> 26) ^ (lfsr >> 14)) & 0x1; - lfsr = (lfsr << 1) | (bit); + fprintf (stderr, "%s", KRED); + fprintf (stderr, " ENC \n"); + fprintf (stderr, "%s", KNRM); } - fprintf (stderr, "%s", KYEL); - fprintf (stderr, " LDU2 ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid); - fprintf(stderr, " Next MI: 0x%016llX \n", lfsr); - fprintf (stderr, "%s", KNRM); - state->payload_miP = lfsr; - } diff --git a/src/rtl_sdr_fm.cpp b/src/rtl_sdr_fm.cpp index 75fb919..f024eea 100644 --- a/src/rtl_sdr_fm.cpp +++ b/src/rtl_sdr_fm.cpp @@ -954,8 +954,10 @@ static void *socket_thread_fn(void *arg) { new_freq = chars_to_int(buffer); dongle.freq = new_freq; // //opts->rtlsdr_center_freq = new_freq; //or dongle.freq, this should update the freq displayed in ncurses terminal hopefully and not do anything naughty + optimal_settings(new_freq, demod.rate_in); rtlsdr_set_center_freq(dongle.dev, dongle.freq); + //verbose_set_frequency (dongle.dev, new_freq); //fprintf (stderr, "Tuning to: %d [Hz] (central freq: %d [Hz])\n", new_freq, new_freq + freq_offset); fprintf (stderr, "Tuning to: %d [Hz] \n", new_freq); } @@ -1042,8 +1044,8 @@ static void *socket_thread_fn(void *arg) { void rtlsdr_sighandler() { - fprintf (stderr, "Signal caught, exiting!\n"); - fprintf (stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C + //fprintf (stderr, "Signal caught, exiting!\n"); + //fprintf (stderr, "Press CTRL + C again to close. Thanks. \n"); //Kindly remind user to double tap CTRL + C rtlsdr_cancel_async(dongle.dev); //cleanup_rtlsdr_stream(); //thank the wraith for this one...if it works...didn't work @@ -1070,6 +1072,7 @@ void open_rtlsdr_stream(dsd_opts *opts) if (opts->rtlsdr_ppm_error > 0 || opts->rtlsdr_ppm_error < 0) { //this way will adjust PPM based on negative values as well dongle.ppm_error = opts->rtlsdr_ppm_error; + fprintf (stderr, "Setting RTL PPM Error Set to %d\n", opts->rtlsdr_ppm_error); } if (opts->audio_in_type == 3) { @@ -1152,6 +1155,8 @@ void cleanup_rtlsdr_stream() safe_cond_signal(&output.ready, &output.ready_m); safe_cond_signal(&controller.hop, &controller.hop_m); pthread_join(controller.thread, NULL); + //add socket thread + //pthread_join(socket_freq, NULL); //dongle_cleanup(&dongle); demod_cleanup(&demod); @@ -1162,16 +1167,29 @@ void cleanup_rtlsdr_stream() } -void get_rtlsdr_sample(int16_t *sample) +//void get_rtlsdr_sample(int16_t *sample) +void get_rtlsdr_sample(int16_t *sample, dsd_opts * opts, dsd_state * state) { if (output.queue.empty()) { + if (opts->use_ncurses_terminal == 1) + { + //ncursesPrinter(opts, state); + //printw ("\n\n\n HELP I'M LOCKED!\n"); + } safe_cond_wait(&output.ready, &output.ready_m); + //goto END; } + pthread_rwlock_wrlock(&output.rw); //*sample = output.queue.front(); *sample = output.queue.front() * volume_multiplier; //try multiplying by numbers here for 'gain' output.queue.pop(); pthread_rwlock_unlock(&output.rw); + // END: + // if (1 == 2) + // { + // fprintf (stderr, "This is a dumb thing to fix"); + // } }