diff --git a/cmake/FindLibPortAudio.cmake b/cmake/FindLibPortAudio.cmake new file mode 100644 index 0000000..67c43e9 --- /dev/null +++ b/cmake/FindLibPortAudio.cmake @@ -0,0 +1,90 @@ +# - Try to find Portaudio +# Once done this will define +# +# PORTAUDIO_FOUND - system has Portaudio +# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory +# PORTAUDIO_LIBRARIES - Link these to use Portaudio +# PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio +# PORTAUDIO_VERSION - Portaudio version +# +# Copyright (c) 2006 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + # in cache already + set(PORTAUDIO_FOUND TRUE) +else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + if (NOT WIN32) + include(FindPkgConfig) + pkg_check_modules(PORTAUDIO2 portaudio-2.0) + endif (NOT WIN32) + + find_path (PORTAUDIO_INCLUDE_DIRS + NAMES + portaudio.h + PATHS + ${PORTAUDIO2_INCLUDEDIR} + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + if (NOT PORTAUDIO_INCLUDE_DIRS) + set (PORTAUDIO_INCLUDE_DIRS + ${PORTAUDIO2_INCLUDE_DIRS} + ) + list (APPEND PORTAUDIO_INCLUDE_DIRS ${PORTAUDIO2_INCLUDEDIR}) + endif (NOT PORTAUDIO_INCLUDE_DIRS) + + find_library (PORTAUDIO_LIBRARIES + NAMES + portaudio + PATHS + ${PORTAUDIO2_LIBDIR} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + if (NOT PORTAUDIO_LIBRARIES) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(PORTAUDIO_LIBRARIES "${PORTAUDIO2_LIBDIR}/lib${PORTAUDIO2_LIBRARIES}.dylib") + else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(PORTAUDIO_LIBRARIES + ${PORTAUDIO2_LIBRARIES} + ) + endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + endif (NOT PORTAUDIO_LIBRARIES) + + if (PORTAUDIO2_VERSION) + set(PORTAUDIO_VERSION + ${PORTAUDIO2_VERSION} + ) + else (PORTAUDIO2_VERSION) + set(PORTAUDIO_VERSION + 18 + ) + endif (PORTAUDIO2_VERSION) + + if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + set(PORTAUDIO_FOUND TRUE) + endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + + if (PORTAUDIO_FOUND) + if (NOT Portaudio_FIND_QUIETLY) + message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}") + endif (NOT Portaudio_FIND_QUIETLY) + else (PORTAUDIO_FOUND) + if (Portaudio_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Portaudio") + endif (Portaudio_FIND_REQUIRED) + endif (PORTAUDIO_FOUND) + + # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view + mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES) + +endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) 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..122311e 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,9 +251,7 @@ 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 @@ -291,9 +259,7 @@ typedef struct 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 split; int playoffset; @@ -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,26 @@ 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 lrrp_file_output; // 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 +357,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 +392,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 +452,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 +485,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 +519,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][84]; //going seven blocks deep by 12 bytes //[slot][value] + uint8_t dmr_34_rate_sf[2][96]; //going six blocks deep by 16 bytes //[slot][value] + 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 +542,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,9 +559,8 @@ 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; //dstar header for ncurses unsigned char dstarradioheader[41]; @@ -604,6 +588,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 +627,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 +668,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 +691,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 +735,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 +772,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 +787,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); @@ -827,9 +835,9 @@ void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8 void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); void ProcessWTFData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); void ProcessUnifiedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]); + //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 +884,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 +898,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..9e98f27 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]); @@ -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..a6ed0f8 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 */ @@ -172,10 +161,7 @@ if (state->currentslot == 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 */ diff --git a/src/dmr_sync.c b/src/dmr_sync.c index 7a85988..662eb26 100644 --- a/src/dmr_sync.c +++ b/src/dmr_sync.c @@ -17,10 +17,35 @@ #include "dsd.h" -//#define PRINT_PI_HEADER_BYTES -//#define PRINT_VOICE_LC_HEADER_BYTES -//#define PRINT_TERMINAISON_LC_BYTES -//#define PRINT_VOICE_BURST_BYTES + +//time_t now; +char * getTimeL(void) //get pretty hh:mm:ss timestamp +{ + time_t t = time(NULL); + + char * curr; + char * stamp = asctime(localtime( & t)); + + curr = strtok(stamp, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + curr = strtok(NULL, " "); + + return curr; +} + +//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; +} //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 @@ -88,25 +113,7 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] unsigned char TrellisReturn[18]; //CDMRTrellisDecode(tdibits, TrellisReturn); //figure out how this works!! CDMRTrellisDecode(tdibits_reverse, TrellisReturn); //NEEDS REVERSE DIBITS! - if (opts->payload == 1) - { - fprintf (stderr,"%s", KCYN); - fprintf (stderr, "\nFull 3/4 Rate Trellis Payload\n "); - for (i = 0; i < 18; i++) - { - fprintf (stderr, "[%02X]", TrellisReturn[i]); - } - fprintf (stderr, "\n Hex to Ascii - "); - for (i = 0; i < 18; i++) - { - if (TrellisReturn[i] <= 0x7E && TrellisReturn[i] >=0x20) - { - fprintf (stderr, "%c", TrellisReturn[i]); - } - else fprintf (stderr, "."); - } - fprintf (stderr,"%s", KNRM); //change back to normal - } + /* Extract the BPTC 196,96 DMR data */ //IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R); // @@ -142,12 +149,21 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] } */ /* Convert the 96 bit of voice LC Header data into 12 bytes */ - k = 0; + + //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; //is this still used? 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] = 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++) { @@ -156,95 +172,70 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01); k++; } - //state->dmr_34_rate_sf[i+36] = ~DmrDataByte[i]; //copy byte to right hand side of shift frame - //state->dmr_34_rate_sf[i+36] = ~TrellisReturn[i]& 0xFF; - state->dmr_34_rate_sf[slot][i+48] = TrellisReturn[i+2]; //plus two to skip the first two bytes - } - if (opts->payload == 2) - { - fprintf (stderr, "%s",KGRN); - fprintf (stderr, "\n Rate 3/4 Superframe - Slot [%d]\n ",slot+1); - for (i = 0; i < (16*4); i++) - { - fprintf (stderr, "[%02X]", state->dmr_34_rate_sf[slot][i]); - if (i == 15 || i == 31 || i == 47) - { - fprintf (stderr, "\n "); //line break and two spaces after each 16 bytes - } - } - fprintf (stderr, "%s ", KNRM); - } - //fprintf (stderr, "%s ", KNRM); - /* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */ - CRCExtracted = 0; - //for(i = 0; i < 24; i++) - 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 + + //state->dmr_34_rate_sf[slot][i+48] = TrellisReturn[i+2]; //plus two to skip the first two bytes + state->dmr_34_rate_sf[slot][i+(blocks*16)] = TrellisReturn[i+2]; //plus two to skip the first two bytes } - //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) - { + //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 { - //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 + //test opening a file with fopen and dumping the LRRP data into it. + //just going to use the same code from EDACS-FM + + //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++) + 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, "\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, " - 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] == 0x34 ) //timestamp + + 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 @@ -252,15 +243,22 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] 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 + 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 ) //lattitude and longitude + + 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; @@ -269,63 +267,113 @@ void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98] 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? + 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) ); + + 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 ) + 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. + //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)); - //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_34_rate_sf[slot][i] == 0x56 ) + if ( state->dmr_34_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_34_rate_sf[slot][i+1] * 2); + 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); + } } - }//end payload fprintf (stderr, "%s ", KNRM); + //Full - if (opts->payload == 2) + if (opts->payload == 1) { - fprintf (stderr, "\nFull 3/4 Rate Payload DmrDataByte (reverse)\n "); + fprintf (stderr,"%s", KCYN); + 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]); + } + fprintf (stderr, "\n Hex to Ascii - "); 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); + if (TrellisReturn[i] <= 0x7E && TrellisReturn[i] >=0x20) + { + fprintf (stderr, "%c", TrellisReturn[i]); + } + else fprintf (stderr, "."); } + fprintf (stderr,"%s", KNRM); //change back to normal } - + //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++) //16, or 18? + { + fprintf (stderr, "[%02X]", state->dmr_34_rate_sf[slot][i]); + 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); + } + state->data_block_counter[state->currentslot]++; //increment block counter } //This is Data Header, why did I name it Data Data @@ -334,13 +382,14 @@ void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint 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 < (16*6); i++) { state->dmr_34_rate_sf[slot][i] = 0; } //clear out the 1/2 rate data superframe so we don't repeat old info - for (short int i = 0; i < (12*3); i++) + for (short int i = 0; i < (12*5); i++) //12*5 = 60 { state->dmr_12_rate_sf[slot][i] = 0; } @@ -446,32 +495,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,6 +673,7 @@ 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]) @@ -1015,14 +1205,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,22 +1225,9 @@ 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); + //state->dmr_12_rate_sf[slot][i+48] = DmrDataByte[i]; //copy byte to right hand side of shift frame + //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) */ @@ -1096,111 +1278,65 @@ 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 + //test opening a file with fopen and dumping the LRRP data into it. + //just going to use the same code from EDACS-FM + + //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 +1344,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 +1368,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 +1393,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,6 +1458,22 @@ 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 16 bytes + { + fprintf (stderr, "\n "); + } + } + fprintf (stderr, "%s ", KNRM); + } + state->data_block_counter[state->currentslot]++; //increment block counter } @@ -1681,6 +1871,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 +1892,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); @@ -1871,8 +2063,9 @@ 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, "%s \n", KGRN); + fprintf (stderr, " Slot %d ", state->currentslot+1); + fprintf(stderr, " 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; @@ -1884,17 +2077,12 @@ void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[19 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); @@ -2093,21 +2281,20 @@ void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[19 //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? 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; } @@ -2552,6 +2739,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..eb5c691 100644 --- a/src/dsd_file.c +++ b/src/dsd_file.c @@ -146,7 +146,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere err = (unsigned char) state->errs2; k = 0; - if (opts->dmr_stereo == 0) + if (opts->dmr_stereo == 0) //was 0, switched while working out des { fprintf (stderr, "\n"); } @@ -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"); //temp disable while I work on DES } } @@ -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..8363c04 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,46 @@ 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 < 84; 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 < 96; 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; + state->dmr_soR = 0; + } void @@ -172,15 +204,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 +224,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 +241,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 +267,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 +280,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 +290,8 @@ 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; + } @@ -255,6 +300,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 +359,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 +424,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 +467,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 +477,46 @@ 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 < 84; 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 < 96; 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 + #ifdef TRACE_DSD state->debug_sample_index = 0; state->debug_label_file = NULL; @@ -447,14 +530,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 +558,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 +579,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 +618,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 +634,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 +652,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 +694,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 +721,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 +831,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 +849,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 +858,7 @@ main (int argc, char **argv) usage (); exit (0); case 'a': - printPortAudioDevices(); + //printPortAudioDevices(); exit(0); case 'e': opts.errorbars = 1; @@ -832,7 +888,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,17 +915,12 @@ 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); - break; - case 'G': //Set rtl device gain sscanf (optarg, "%d", &opts.rtl_gain_value); //multiple value by ten to make it consitent with the way rtl_fm really works break; @@ -877,11 +929,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 +945,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 +966,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 +1035,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 +1064,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 +1080,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 +1152,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 +1160,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 +1229,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 +1310,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 +1321,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 +1361,6 @@ main (int argc, char **argv) } } - if (opts.use_ncurses_terminal == 1) - { - ncursesOpen(); - } - if (opts.resume > 0) { openSerial (&opts, &state); @@ -1314,23 +1376,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 +1391,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 +1414,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 +1434,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..a0eb63f 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,27 @@ 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); + if (1 == 1) //still not quite right //state->payload_algid == 0 || state->K != 0 + { + mbe_processAmbe2450Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, + ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality); + } //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 +260,23 @@ 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); + if (1 == 1) //state->payload_algidR == 0 || state->K != 0 + { + 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 +285,7 @@ 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 ??? 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); @@ -294,4 +333,18 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a 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) + { + //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) + { + //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..622200f 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 ENC P25 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)", //better name + "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,909 @@ 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) + { + //still disabled until a fix is found + if (opts->unmute_encrypted_p25 == 0) + { + opts->unmute_encrypted_p25 = 1; + } + else opts->unmute_encrypted_p25 = 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)) + { + //state->symbolfile = fopen("adp_fdma.bin", "r"); + 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 + } + + //Burger King + 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(); + if (state->K > 255) + { + state->K = 255; + } + 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); + } + + 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); + } + + } + + +} +//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/menues 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 + 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; + } //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, " "); } @@ -252,13 +1281,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; + } //P25 @@ -362,6 +1394,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 +1426,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 +1459,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 +1494,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 +1541,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 +1551,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 +1627,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 +1635,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 +1660,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 +1728,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 +1736,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 +1752,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 +1829,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 +1837,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 +1853,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 +1930,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..a1d9bfd 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)); 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..fdd6ef5 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,17 +773,19 @@ 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); - + //print scrambler key value if manually inserted + if (state->nxdn_cipher_type == 0x01 && state->R > 0) //scrambler + { + fprintf (stderr, "%s", KYEL); + fprintf(stderr, "Value: 0x%04llX", state->R); //use R and not miN + fprintf (stderr, "%s", KNRM); + } if(state->NxdnElementsContent.VCallCrcIsGood) { @@ -784,7 +805,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 +836,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); + //let's load this mother fucker up then lol + 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 +1027,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_ldu1.c b/src/p25p1_ldu1.c index 2c6fe5f..f309fc6 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); @@ -174,6 +168,7 @@ processLDU1 (dsd_opts* opts, dsd_state* state) { lsd2[i] = lsd[i] + '0'; } + //skip two octets since LSD is part of the encryption portion // TODO: error correction of the LSD bytes... // TODO: do something useful with the LSD bytes... diff --git a/src/p25p1_ldu2.c b/src/p25p1_ldu2.c index 3611cb3..5ff8e3d 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]; @@ -174,6 +169,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state) { lsd2[i] = lsd[i] + '0'; } + //skip two octets since LSD is part of the encryption portion // TODO: error correction of the LSD bytes... // TODO: do something useful with the LSD bytes... @@ -185,6 +181,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 +372,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"); + // } }