22 Commits

Author SHA1 Message Date
lwvmobile
ef07b48540 DMR Minor Code Fixes; 2023-02-04 20:10:38 -05:00
lwvmobile
db67a8b227 NCurses Compiler Warning and Call Alert Fix; 2023-02-04 04:35:06 -05:00
lwvmobile
4e2c4577d5 DMR Cap+ CSBK Improvements; 2023-02-03 22:15:13 -05:00
lwvmobile
e581c96560 DMR FLCO Tweaks; P25 Site/RFSS Display; 2023-02-02 20:03:52 -05:00
lwvmobile
f3505269d0 DMR Conf Data CRC9; Message CRC32; Tweaks; 2023-02-01 05:35:21 -05:00
lwvmobile
20ccdbbced DMR FLC Tweaks; CSBK Cleaning; 2023-02-01 05:31:40 -05:00
lwvmobile
fc2fb99502 P25P2 OSS Bugfix; 2023-01-29 18:41:03 -05:00
lwvmobile
143c560958 DMR FLCO - Check PF First; 2023-01-29 16:09:47 -05:00
lwvmobile
d122d7e935 DMR Unknown FLCO Tweaks; PI Tweaks; 2023-01-28 21:00:13 -05:00
lwvmobile
d0f9bb4bad Fix DMR FEC/CRC/RAS Implementation Issues; 2023-01-21 05:43:42 -05:00
lwvmobile
ac752029bd Tweak RAS/CRC; Other Misc Tweaks; 2023-01-19 09:42:42 -05:00
lwvmobile
5b994f5129 NXDN Multi-Key CSV Import; Example Updt; 2023-01-18 12:18:56 -05:00
lwvmobile
ec7d7c24a5 DMR SB/RC Additions; Cap+ LC/CSBK; RAS; 2023-01-17 23:58:52 -05:00
lwvmobile
1d49481f2d Fix/Restore MBEout Files; 'DSP' CACH; Tweaks; 2023-01-17 02:25:53 -05:00
lwvmobile
7ca8cb421c Cap+ FLC/CSBK Tweaks; 2023-01-17 02:08:25 -05:00
lwvmobile
4eb44b3c67 'DSP' File Output for OKDMR - Initial Commit; 2023-01-15 22:04:04 -05:00
lwvmobile
e16e4b61fc Cap+ Things; 2023-01-15 21:22:28 -05:00
lwvmobile
fbd04fa869 Allow Standard BP Key on MBE File Playback; 2023-01-15 18:13:48 -05:00
lwvmobile
7f9b852f36 Fix Audio Gain/Device Out on MBE File Playback; 2023-01-15 18:12:15 -05:00
lwvmobile
f5a7ab2b77 P25 P2 ISCH Var Fix; 2023-01-15 18:09:47 -05:00
lwvmobile
ffe6098fb8 DMR Cap+ Rest Channel FLCO/SLCO Fix; 2023-01-09 19:39:05 -05:00
lwvmobile
157ca8c043 RTL Input Tuning Fix (UDP); Minor Tweaks; 2023-01-09 14:13:00 -05:00
31 changed files with 2215 additions and 900 deletions

View File

@@ -1,7 +1,3 @@
## Notice
These examples will need to be modified to run on the 'lite' branch, or any precompiled Windows binaries released. (i.e. dsd-fme to dsd-fme-lite.exe, -i pulse -o pulse, etc)
### Example Usage and Notes!
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25 (1 and 2) . To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
@@ -125,7 +121,7 @@ For Connect Plus, enumerate your list from 1 to the last channel and add the fre
Currently uncoded/unknown DMR trunking systems include Hytera XPT.
Trunking Note4: NXDN Trunking may also require a channel map file, depending on the system. If it uses a custom range (above 800), then channels will need to be mapped. If channels do not require mapping (have channels below 800) but you are not tuning properly, then please use a channel_map and please report the issue in the issues along with the channels you are tuning and the actual rf frequency so corrections can be made.
Trunking Note4: NXDN TRunking will require a channel map. Please see the example folder for an appropriate channel map. ~NXDN Trunking may also require a channel map file, depending on the system. If it uses a custom range (above 800), then channels will need to be mapped. If channels do not require mapping (have channels below 800) but you are not tuning properly, then please use a channel_map and please report the issue in the issues along with the channels you are tuning and the actual rf frequency so corrections can be made.~
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.

View File

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

5
examples/nxdn_sc_key.csv Normal file
View File

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

View File

@@ -203,8 +203,10 @@ typedef struct
int playoffsetR;
char mbe_out_dir[1024];
char mbe_out_file[1024];
char mbe_out_fileR[1024]; //second slot on a TDMA system
char mbe_out_path[2048]; //1024
FILE *mbe_out_f;
FILE *mbe_out_fR; //second slot on a TDMA system
FILE *symbol_out_f;
float audio_gain;
float audio_gainR;
@@ -218,6 +220,7 @@ typedef struct
char szNumbers[1024]; //**tera 10/32/64 char str
short int symbol_out;
short int mbe_out; //flag for mbe out, don't attempt fclose more than once
short int mbe_outR; //flag for mbe out, don't attempt fclose more than once
SNDFILE *wav_out_f;
SNDFILE *wav_out_fR;
SNDFILE *wav_out_raw;
@@ -327,7 +330,8 @@ typedef struct
//csv import filenames
char group_in_file[1024];
char lcn_in_file[1024];
char chan_in_file[1024];
char chan_in_file[1024];
char key_in_file[1024];
//end import filenames
//reverse mute
@@ -355,6 +359,10 @@ typedef struct
//OSS audio - slot preference
uint8_t slot_preference;
//'DSP' Format Output
uint8_t use_dsp_output;
char dsp_out_file[2048];
} dsd_opts;
typedef struct
@@ -508,9 +516,11 @@ typedef struct
unsigned int dmr_fid;
unsigned int dmr_so;
unsigned int dmr_flco;
unsigned int dmr_fidR;
unsigned int dmr_soR;
unsigned int dmr_flcoR;
char slot1light[8];
char slot2light[8];
@@ -527,8 +537,9 @@ typedef struct
//new stuff below here
uint8_t data_conf_data[2]; //flag for confirmed data blocks per slot
uint8_t dmr_pdu_sf[2][288]; //unified pdu 'superframe' //[slot][byte]
uint8_t cap_plus_csbk_bits[12*8*4]; //CSBK Cap+ FL initial and appended block bit storage
uint8_t data_block_crc_valid[2][25]; //flag each individual block as good crc on confirmed data
char dmr_embedded_signalling[2][6][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
char dmr_embedded_signalling[2][7][48]; //embedded signalling 2 slots by 6 vc by 48 bits (replacing TS1SuperFrame.TimeSlotRawVoiceFrame.Sync structure)
char dmr_cach_fragment[4][17]; //unsure of size, will need to check/verify
int dmr_cach_counter; //counter for dmr_cach_fragments 0-3; not sure if needed yet.
@@ -572,6 +583,8 @@ typedef struct
unsigned long long int p2_wacn;
unsigned long long int p2_sysid;
unsigned long long int p2_cc; //p1 NAC
unsigned long long int p2_siteid;
unsigned long long int p2_rfssid;
int p2_hardset; //flag for checking whether or not P2 wacn and sysid are hard set by user
int p2_scramble_offset; //offset counter for scrambling application
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
@@ -641,6 +654,9 @@ typedef struct
uint32_t nxdn_location_sys_code;
uint16_t nxdn_location_site_code;
//multi-key array for nxdn keys
unsigned long long int rkey_array[0x1FF];
//dmr late entry mi
uint64_t late_entry_mi_fragment[2][7][3];
@@ -750,13 +766,16 @@ int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_a
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d); //tdma slot 2
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d);
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d);
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
void openMbeInFile (dsd_opts * opts, dsd_state * state);
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
void openMbeOutFile (dsd_opts * opts, dsd_state * state);
void openMbeOutFileR (dsd_opts * opts, dsd_state * state); //tdma slot 2
void openWavOutFile (dsd_opts * opts, dsd_state * state);
void openWavOutFileL (dsd_opts * opts, dsd_state * state);
void openWavOutFileR (dsd_opts * opts, dsd_state * state);
@@ -869,7 +888,7 @@ int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]);
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output);
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3]);
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32]);
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd);
//Reed Solomon (12,9) functions
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome);
@@ -882,6 +901,8 @@ uint16_t ComputeCrcCCITT(uint8_t * DMRData);
uint16_t ComputeCrcCCITT16d(const uint8_t buf[], uint8_t len);
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask);
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData);
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData);
//new simplified dmr functions
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
@@ -917,10 +938,14 @@ void dmr_alg_refresh (dsd_opts * opts, dsd_state * state);
void dmr_late_entry_mi_fragment (dsd_opts * opts, dsd_state * state, uint8_t vc, char ambe_fr[4][24], char ambe_fr2[4][24], char ambe_fr3[4][24]);
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state);
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power);
//DMR FEC/CRC from Boatbod - OP25
bool Hamming17123(uint8_t* d);
uint8_t crc8(uint8_t bits[], unsigned int len);
bool crc8_ok(uint8_t bits[], unsigned int len);
uint8_t crc7(uint8_t bits[], unsigned int len);
//LFSR code courtesy of https://github.com/mattames/LFSR/
void LFSR(dsd_state * state);
@@ -1009,6 +1034,7 @@ unsigned long long int edacs_bch (unsigned long long int message);
int csvGroupImport(dsd_opts * opts, dsd_state * state);
int csvLCNImport(dsd_opts * opts, dsd_state * state);
int csvChanImport(dsd_opts * opts, dsd_state * state);
int csvKeyImport(dsd_opts * opts, dsd_state * state);
#ifdef __cplusplus
extern "C" {
@@ -1034,7 +1060,7 @@ bool CDMRTrellisDecode(const unsigned char* data, unsigned char* payload);
int ez_rs28_ess (int payload[96], int parity[168]); //ezpwd bridge for FME
int ez_rs28_facch (int payload[156], int parity[114]); //ezpwd bridge for FME
int ez_rs28_sacch (int payload[180], int parity[132]); //ezpwd bridge for FME
unsigned long long int isch_lookup (unsigned long long int isch); //isch map lookup
int isch_lookup (unsigned long long int isch); //isch map lookup
int bd_bridge (int payload[196], uint8_t decoded[12]); //bridge to Michael Ossmann Block De-interleaver and 1/2 rate trellis decoder
int crc16_lb_bridge (int payload[190], int len);
int crc12_xb_bridge (int payload[190], int len);

View File

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

View File

@@ -51,7 +51,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
if ( (state->data_header_format[slot] & 0xF) == 0xD) //DD_HEAD
{
state->data_conf_data[slot] = 0;
//The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set
//to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.1.2
if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit
{
state->data_conf_data[slot] = 1;
}
else state->data_conf_data[slot] = 0;
state->data_header_padding[slot] = dheader[7] & 0xF;
state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) ); //what a pain MSB | LSB
fprintf (stderr, "\n Short Data - Defined: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X",
@@ -61,7 +68,14 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
if ( (state->data_header_format[slot] & 0xF) == 0xE) //SP_HEAD or R_HEAD
{
state->data_conf_data[slot] = 0;
//The Response Requested (A) information element of the header shall be set to 0 for unconfirmed data and shall be set
//to 1 for confirmed data. ETSI TS 102 361-3 V1.2.1 (2013-07) - 6.2.2
if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit
{
state->data_conf_data[slot] = 1;
}
else state->data_conf_data[slot] = 0;
state->data_header_padding[slot] = dheader[7] & 0xF;
state->data_header_blocks[slot] = ( (dheader[0] & 0x30) | ((dheader[1] & 0xF) >> 0) );
fprintf (stderr, "\n Short Data - Raw or Precoded: DPF %01X - SAP %02X - Appended Blocks %02X - Padding Bits %02X",
@@ -247,11 +261,11 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_
fprintf (stderr, "%s ", KNRM);
//let user know the data header may have errors
fprintf (stderr, "%s", KRED);
if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
else if(IrrecoverableErrors == 0) fprintf(stderr, " (FEC OK)");
else fprintf(stderr, " (FEC/CRC ERR)");
fprintf (stderr, "%s", KNRM);
// fprintf (stderr, "%s", KRED);
// if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
// else if(IrrecoverableErrors == 0) fprintf(stderr, " (FEC OK)");
// else fprintf(stderr, " (FEC/CRC ERR)");
// fprintf (stderr, "%s", KNRM);
}
@@ -261,16 +275,17 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
int i, j, k;
uint8_t lb = 0; //mbc last block
uint8_t pf = 0; //mbc protect flag
uint8_t is_conf_data = 0; //internal flag to see if type 1 blocks contain confirmed data crcs and serials
// uint8_t is_conf_data = 0; //internal flag to see if type 1 blocks contain confirmed data crcs and serials
uint8_t slot = state->currentslot;
int blocks;
uint8_t blockcounter = state->data_block_counter[slot];
uint8_t block_num = state->data_header_blocks[slot];
//crc specific variables
uint8_t len = 24; //len of completed message needing crc32 number of blocks*block_len - 12?
uint8_t crclen = 32; //len of the crc32 (obviously)
uint8_t start = 12; //starting position (+12 offset loaded up data header)
uint8_t n = 12; //number of bytes per block
// uint8_t len = 24;
// uint8_t crclen = 32; //len of the crc32 (obviously)
// uint8_t start = 12; //starting position (+12 offset loaded up data header)
// uint8_t n = 12; //number of bytes per block
//TODO: CRC check on Header, Blocks and full frames as appropriate
uint32_t CRCCorrect = 0;
@@ -278,7 +293,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
uint32_t CRCExtracted = 0;
uint32_t IrrecoverableErrors = 0;
uint8_t dmr_pdu_sf_bits[18*8*8]; //8 blocks at 18 bytes at 8 bits //just a large value to have plenty storage space
uint8_t dmr_pdu_sf_bits[8*8*50]; //give plenty of space so we don't go oob
//MBC Header and Block CRC
uint8_t mbc_crc_good[2]; //header and blocks crc pass/fail local storage
@@ -293,7 +308,8 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
if (block_len == 0) block_len = 18;
if (block_len > 24) block_len = 24;
//TODO: add CRC/FEC validation to each data header and each confirmed data block as well - type 1
//WIP: CRC32 on Completed Message Working! CRC9 on 3/4 Working! CRC9 or 1/2 and 1 still need testing - type 1
//may/will still fail on p_head data and blocks
if (type == 1)
{
//type 1 data block, shuffle method
@@ -312,8 +328,79 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
//time to send the completed 'superframe' to the DMR PDU message handler
if (state->data_block_counter[slot] == state->data_header_blocks[slot])
{
//TODO: CRC32 on completed messages
dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]);
//CRC32 on completed messages
for(i = 0, j = 0; i < (block_num * block_len); i++, j+=8)
{
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
dmr_pdu_sf_bits[j + 2] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
dmr_pdu_sf_bits[j + 3] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
dmr_pdu_sf_bits[j + 4] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
dmr_pdu_sf_bits[j + 5] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
dmr_pdu_sf_bits[j + 6] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
}
//sanity check to prevent a negative or zero block_num or sending a negative value into the bit array
if (block_num < 1 || block_num == 0) block_num = 1;
CRCExtracted = 0;
//extract crc from last block, apply to completed 'superframe' minus header
for(i = 0; i < 32; i++)
{
CRCExtracted = CRCExtracted << 1;
CRCExtracted = CRCExtracted | (uint32_t)(dmr_pdu_sf_bits[i + (block_len * 8) * block_num - 32] & 1); //96
}
//rearrage for ridiculously stupid CRC32 LSO/MSO ordering
for(i = 0, j = 0; i < (block_num * block_len); i+=2, j+=16)
{
dmr_pdu_sf_bits[j + 0] = (state->dmr_pdu_sf[slot][i+1] >> 7) & 0x01;
dmr_pdu_sf_bits[j + 1] = (state->dmr_pdu_sf[slot][i+1] >> 6) & 0x01;
dmr_pdu_sf_bits[j + 2] = (state->dmr_pdu_sf[slot][i+1] >> 5) & 0x01;
dmr_pdu_sf_bits[j + 3] = (state->dmr_pdu_sf[slot][i+1] >> 4) & 0x01;
dmr_pdu_sf_bits[j + 4] = (state->dmr_pdu_sf[slot][i+1] >> 3) & 0x01;
dmr_pdu_sf_bits[j + 5] = (state->dmr_pdu_sf[slot][i+1] >> 2) & 0x01;
dmr_pdu_sf_bits[j + 6] = (state->dmr_pdu_sf[slot][i+1] >> 1) & 0x01;
dmr_pdu_sf_bits[j + 7] = (state->dmr_pdu_sf[slot][i+1] >> 0) & 0x01;
dmr_pdu_sf_bits[j + 8] = (state->dmr_pdu_sf[slot][i] >> 7) & 0x01;
dmr_pdu_sf_bits[j + 9] = (state->dmr_pdu_sf[slot][i] >> 6) & 0x01;
dmr_pdu_sf_bits[j + 10] = (state->dmr_pdu_sf[slot][i] >> 5) & 0x01;
dmr_pdu_sf_bits[j + 11] = (state->dmr_pdu_sf[slot][i] >> 4) & 0x01;
dmr_pdu_sf_bits[j + 12] = (state->dmr_pdu_sf[slot][i] >> 3) & 0x01;
dmr_pdu_sf_bits[j + 13] = (state->dmr_pdu_sf[slot][i] >> 2) & 0x01;
dmr_pdu_sf_bits[j + 14] = (state->dmr_pdu_sf[slot][i] >> 1) & 0x01;
dmr_pdu_sf_bits[j + 15] = (state->dmr_pdu_sf[slot][i] >> 0) & 0x01;
//increment extra 2 bytes on each nth byte (depends on data type 1/2, 3/4, 1) if conf data
if ( i == (block_len - 1) )
{
if (state->data_conf_data[slot] == 0) i+=2;
}
}
//confirmed working now!
CRCComputed = (uint32_t)ComputeCrc32Bit(dmr_pdu_sf_bits, ( block_num * block_len * 8) - 32);
//if the CRC32 is correct, I think its fair to assume we don't need to worry about if the
//individual CRC9s are correct on confirmed data blocks (but we can confirm now that they are all good)
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
//test only running on good CRC or CRC/RAS bypass (aggressive_framesync)
if (CRCCorrect || opts->aggressive_framesync == 0) dmr_pdu (opts, state, block_len, state->dmr_pdu_sf[slot]);
if (CRCCorrect) ; //print nothing
else
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, "\n Slot %d - Multi Block PDU Message CRC32 ERR", slot+1);
fprintf (stderr, "%s", KNRM);
state->data_conf_data[slot] = 0; //flag off conf data flag
state->data_header_format[slot] = 0; //zero out so we don't keep ascii printing
}
}
}
@@ -387,6 +474,12 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
CRCCorrect = 1;
IrrecoverableErrors = 0;
}
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
//cspdu will only act on any fid/opcodes if good CRC to prevent falsing on control signalling
dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors);
@@ -398,7 +491,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
if (opts->payload == 1 && type == 1 && state->data_block_counter[slot] == state->data_header_blocks[slot])
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, "\n Multi Block PDU Superframe - Slot [%d]\n ", slot+1);
fprintf (stderr, "\n Slot %d - Multi Block PDU Message\n ", slot+1);
for (i = 0; i < ((blocks+1)*block_len); i++)
{
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
@@ -407,6 +500,10 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
fprintf (stderr, "\n ");
}
}
//debug print
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
fprintf (stderr, "%s ", KNRM);
}
@@ -414,7 +511,7 @@ void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_byte
if (opts->payload == 1 && type == 2 && lb == 1)
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, "\n MBC Multi Block PDU Superframe - Slot [%d]\n ", slot+1);
fprintf (stderr, "\n Slot %d - Multi Block Control Message\n ", slot+1);
for (i = 0; i < ((blocks+1)*block_len); i++)
{
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
@@ -459,4 +556,5 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
memset (state->dmr_lrrp_source, 0, sizeof(state->dmr_lrrp_source));
memset (state->dmr_cach_fragment, 1, sizeof (state->dmr_cach_fragment));
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
}

View File

@@ -41,6 +41,11 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
uint8_t internalslot;
uint8_t vc1;
uint8_t vc2;
//assign as nonsensical numbers
uint8_t cc = 25;
uint8_t power = 9; //power and pre-emption indicator
uint8_t lcss = 9;
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
uint8_t dummy_bits[196];
@@ -189,13 +194,13 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
syncdata[(2*i)+1] = (1 & dibit); // bit 0
//embedded link control
if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E
{
state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1
state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0
}
if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D and E
{
state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1
state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0
@@ -265,6 +270,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
else fprintf (stderr,"Sync: -DMR ");
vc1 = 1;
//close MBEout file - slot 1
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
if (internalslot == 1)
{
@@ -276,6 +284,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
vc2 = 1;
//close MBEout file - slot 2
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
dmr_data_sync (opts, state);
skipcount++;
@@ -294,9 +305,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
else if (emb_ok == 1)
{
uint8_t cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
uint8_t power = EmbeddedSignalling[4];
uint8_t lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
power = EmbeddedSignalling[4];
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
}
@@ -312,12 +323,16 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
state->dmrburstL = 16;
vc = vc1;
sprintf (light, "%s", " [SLOT1] slot2 ");
//open MBEout file - slot 1
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
}
else
{
state->dmrburstR = 16;
vc = vc2;
sprintf (light, "%s", " slot1 [SLOT2] ");
//open MBEout file - slot 2
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
}
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
else sprintf (polarity, "%s", "-");
@@ -329,6 +344,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
//process embedded link control
fprintf (stderr, "\n");
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
//check the single burst/reverse channel opportunity
dmr_sbrc (opts, state, power);
}
if (internalslot == 1 && vc2 == 6)
@@ -336,6 +353,8 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
//process embedded link control
fprintf (stderr, "\n");
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
//check the single burst/reverse channel opportunity
dmr_sbrc (opts, state, power);
}
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
@@ -382,12 +401,37 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
{
state->last_vc_sync_time = time(NULL);
state->last_cc_sync_time = time(NULL);
}
//'DSP' output to file
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
for (i = 0; i < 6; i++) //3 byte CACH
{
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", cach_byte);
}
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for voice burst
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
//reset err checks
cach_err = 1;
tact_okay = 0;
emb_ok = 0;
//reset emb components
cc = 25;
power = 9;
lcss = 9;
//Extra safeguards to break loop
// if ( (vc1 > 7 && vc2 > 7) ) goto END;
@@ -420,6 +464,10 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
state->errs2R = 0;
state->errs2 = 0;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
//if we have a tact or emb err, then produce sync pattern/err message
if (tact_okay != 1 || emb_ok != 1)
{
@@ -471,6 +519,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
uint8_t cach_err = 0;
uint8_t sync_okay = 1;
uint8_t internalslot;
char cachdata[25];
int cachInterleave[24] =
@@ -503,10 +552,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i] = dibit;
}
@@ -534,7 +580,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
}
}
state->currentslot = tact_bits[1];
internalslot = state->currentslot = tact_bits[1];
//Setup for first AMBE Frame
@@ -601,6 +647,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 18; i++)
{
dibit = getDibit(opts, state);
state->dmr_stereo_payload[i+90] = dibit;
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
@@ -623,6 +670,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 36; i++)
{
dibit = getDibit(opts, state);
state->dmr_stereo_payload[i+108] = dibit;
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
@@ -633,6 +681,26 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
}
//'DSP' output to file
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
for (i = 0; i < 6; i++) //3 byte CACH
{
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", cach_byte);
}
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for "voice burst"
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
fprintf (stderr,"%s ", getTime());
char polarity[3];
char light[18];
@@ -640,10 +708,14 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
if (state->currentslot == 0)
{
sprintf (light, "%s", " [SLOT1] slot2 ");
//open MBEout file - slot 1
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
}
else
{
sprintf (light, "%s", " slot1 [SLOT2] ");
//open MBEout file - slot 2
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
}
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
else sprintf (polarity, "%s", "-");
@@ -665,7 +737,7 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
//collect the mi fragment
dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3);
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
cach_err = dmr_cach (opts, state, cachdata);
fprintf (stderr, "\n");

View File

@@ -234,7 +234,7 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " Move (C_MOVE) (TODO)");
fprintf (stderr, " Move (C_MOVE) ");
}
//Aloha
@@ -372,10 +372,10 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " Clear (P_CLEAR) (TODO)");
fprintf (stderr, " Clear (P_CLEAR) ");
}
//(P_PROTECT) - Could be a useful way of determining who is on the current timeslot p_kind 2
//(P_PROTECT)
if (csbk_o == 47)
{
//initial line break
@@ -395,27 +395,6 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
fprintf (stderr, "\n");
fprintf (stderr, " Target [%08d] - Source [%08d]", target, source);
//Illegally Parked is another way to say a private call is outbound on this channel
//so, we can use this as a form of 'link control'
if (p_kind == 2)
{
//don't set this if operating out of dmr mono or using call alert beep
if (opts->dmr_mono == 0 && opts->call_alert == 0)
{
if (state->currentslot == 0)
{
state->lasttg = target;
state->lastsrc = source;
}
else
{
state->lasttgR = target;
state->lastsrcR = source;
}
}
}
}
if (csbk_o == 40) //0x28 //check to see if these are fid 0 only, or also in other manufacturer fids
@@ -545,28 +524,28 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " C_AHOY (TODO) ");
fprintf (stderr, " C_AHOY ");
}
if (csbk_o == 42)
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " P_MAINT (TODO) ");
fprintf (stderr, " P_MAINT ");
}
if (csbk_o == 30)
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " C_ACKVIT (TODO) ");
fprintf (stderr, " C_ACKVIT ");
}
if (csbk_o == 31)
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, " C_RAND (TODO) ");
fprintf (stderr, " C_RAND ");
}
//tier 2 csbks
@@ -641,39 +620,55 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
}
//Capacity+ Section
//Reworked Cap+ for Multi Block FL PDU and Private/Data Calls
//experimental, but seems to be working well
if (csbk_fid == 0x10)
{
//not quite sure how these tuning rules will go over
//if they don't work so well, may just fall back to
//a 'follow rest channel on no sync' only approach
//Cap+ Channel Status PDU
if (csbk_o == 0x3E)
{
//initial line break
fprintf (stderr, "\n");
fprintf (stderr, "%s", KYEL);
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
uint8_t slot = cs_pdu_bits[18];
uint8_t rest_channel = cs_pdu[2] & 0xF; //0xF, or 0x1F?
uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
uint8_t ts = cs_pdu_bits[18]; //timeslot this PDU occurs in
uint8_t res = cs_pdu_bits[19]; //unknown, always seems to be 0
uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
uint8_t group_tally = 0; //set this to the number of active group channels tallied
uint8_t ch[8]; //one bit per channel
uint8_t pch[8]; //private or data call channel bits
uint8_t tg = 0;
uint32_t tghex = 0; //combined all tgs for debug
int i, j, k;
//tg and channel info for trunking purposes
uint8_t t_tg[9];
memset (t_tg, 0, sizeof(t_tg));
k = 0;
//initialize group ch and private/data channel bit arrays
for (i = 0; i < 8; i++)
{
ch[i] = 0;
pch[i] = 0;
}
//treating FL as a form of LCSS
if (fl != 1) //initial or single block (fl2 or fl3)
{
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
for (i = 0; i < 10*8; i++) state->cap_plus_csbk_bits[i] = cs_pdu_bits[i];
}
else //appended block (fl1)
{
for (i = 0; i < 7*8; i++) state->cap_plus_csbk_bits[i+80] = cs_pdu_bits[i+24];
}
if (rest_channel != state->dmr_rest_channel)
{
state->dmr_rest_channel = rest_channel;
}
for (int i = 0; i < 8; i++)
{
ch[i] = cs_pdu_bits[i+24];
}
//assign to cc freq to follow during no sync
if (state->trunk_chan_map[rest_channel] != 0)
@@ -682,95 +677,297 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
//set to always tuned
opts->p25_is_tuned = 1;
}
fprintf (stderr, " Capacity Plus Channel Status - Rest Channel %d", rest_channel);
fprintf (stderr, "\n ");
for (i = 0; i < 8; i++)
fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
if (fl == 1) fprintf (stderr, " - Appended Block");
if (fl == 2) fprintf (stderr, " - Initial Block");
if (fl == 3) fprintf (stderr, " - Single Block");
//look at each group channel bit -- run this PRIOR to checking private or data calls
//or else we will overwrite the ch bits we set below for private calls with zeroes
//these also seem to indicate data calls -- can't find a distinction of which is which
for (int i = 0; i < 8; i++)
{
fprintf (stderr, "Ch%d: ", i+1);
if (ch[i] != 0)
ch[i] = state->cap_plus_csbk_bits[i+24];
if (ch[i] == 1) group_tally++; //figure out where to start looking in the byte stream for the 0x80 flag
}
//check for private/data calls
uint8_t pdflag = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[40+(group_tally*8)], 8); //seems to be 0x80 (last block flag?) on samples I have
uint16_t private_target = 0;
//first, check to see if we have a completed PDU
if (fl != 2)
{
//then check to see if this byte has a value, should be 0x80
//this bytes location seems to shift depending on level of activity
if (pdflag != 0) //now looking to see if any appended data was added
{
tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8);
fprintf (stderr, " %03d ", tg);
//add values to trunking tg/channel potentials
t_tg[i] = tg;
k++;
k = 0; //= 0
fprintf (stderr, "\n");
fprintf (stderr, " F%X Private or Data Call", pdflag);
for (int i = 0; i < 8; i++)
{
pch[i] = state->cap_plus_csbk_bits[i+48+(group_tally*8)];
if (pch[i] == 1)
{
fprintf (stderr, " Ch%d:", i+1);
private_target = (uint16_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[56+(k*16)+(group_tally*8)], 16);
fprintf (stderr, " TGT %d;", private_target);
if (opts->trunk_tune_private_calls == 1) t_tg[i] = private_target; //set here for tuning allow/block
k++;
}
}
}
}
//end private/data call check
if (fl != 2)
{
fprintf (stderr, "\n ");
k = 0;
for (i = 0; i < 8; i++)
{
fprintf (stderr, "Ch%d: ", i+1);
if (ch[i] == 1) //group voice channels
{
tg = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[k*8+32], 8);
if (tg != 0) fprintf (stderr, " %03d ", tg);
else fprintf (stderr, "Actv ");
//add values to trunking tg/channel potentials
t_tg[i] = tg;
if (tg != 0) k++;
}
else if (pch[i] == 1) //private or data channels
{
fprintf (stderr, "P||D ");
//flag as available for tuning if enabled
if (opts->trunk_tune_private_calls == 1) ch[i] = 1;
}
else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
else fprintf (stderr, "Idle ");
if (i == 3) fprintf (stderr, "\n ");
}
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
fprintf (stderr, "%s", KNRM);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
//don't tune if vc on the current channel
if ( (time(NULL) - state->last_vc_sync_time > 2) )
{
for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
{
char mode[8]; //allow, block, digital, enc, etc
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == t_tg[j])
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
}
}
//without priority, this will tune the first one it finds (if group isn't blocked)
if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
{
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
{
//RIGCTL
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
j = 11; //break loop
}
//rtl_udp
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
opts->p25_is_tuned = 1;
j = 11; //break loop
}
}
}
}
} //end tuning
SKIPCAP: ;
//debug print
if (fl == 1 && opts->payload == 1)
{
fprintf (stderr, "%s\n", KYEL);
fprintf (stderr, " CAP+ Multi Block PDU ");
uint8_t fl_bytes = 0;
for (i = 0; i < 17; i++)
{
fl_bytes = (uint8_t)ConvertBitIntoBytes(&state->cap_plus_csbk_bits[i*8], 8);
fprintf (stderr, "[%02X]", fl_bytes);
}
fprintf (stderr, "%s", KNRM);
}
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
} //fl != 2
} //opcode == 0x3E
} //fid == 0x10
//Capacity+ Section -- fallback if issues arise
// if (csbk_fid == 0x10)
// {
// //not quite sure how these tuning rules will go over
// //if they don't work so well, may just fall back to
// //a 'follow rest channel on no sync' only approach
// if (csbk_o == 0x3E)
// {
// //initial line break
// fprintf (stderr, "\n");
// fprintf (stderr, "%s", KYEL);
// uint8_t fl = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 2);
// uint8_t ts = cs_pdu_bits[18]; //accurate?
// uint8_t res = cs_pdu_bits[19]; //unknown??
// uint8_t rest_channel = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[20], 4);
// uint8_t ch[8]; //one bit per channel
// uint8_t tg = 0;
// uint32_t tghex = 0; //combined all tgs for debug
// int i, j, k;
// //tg and channel info for trunking purposes
// uint8_t t_tg[9];
// memset (t_tg, 0, sizeof(t_tg));
// k = 0;
// if (rest_channel != state->dmr_rest_channel)
// {
// state->dmr_rest_channel = rest_channel;
// }
// for (int i = 0; i < 8; i++)
// {
// ch[i] = cs_pdu_bits[i+24];
// }
// //assign to cc freq to follow during no sync
// if (state->trunk_chan_map[rest_channel] != 0)
// {
// state->p25_cc_freq = state->trunk_chan_map[rest_channel];
// //set to always tuned
// opts->p25_is_tuned = 1;
// }
// fprintf (stderr, " Capacity Plus Channel Status - FL: %d TS: %d RS: %d - Rest Channel %d", fl, ts, res, rest_channel);
// fprintf (stderr, "\n ");
// for (i = 0; i < 8; i++)
// {
// fprintf (stderr, "Ch%d: ", i+1);
// if (ch[i] != 0)
// {
// tg = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[k*8+32], 8);
// if (tg != 0) fprintf (stderr, " %03d ", tg);
// else fprintf (stderr, "Priv "); //observed 000s for TG value seem to appear during a Cap+ Private TXI call
// //add values to trunking tg/channel potentials
// t_tg[i] = tg;
// k++;
}
else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
else fprintf (stderr, "Idle ");
// }
// else if (i+1 == rest_channel) fprintf (stderr, "Rest ");
// else fprintf (stderr, "Idle ");
if (i == 3) fprintf (stderr, "\n ");
}
tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
//fprintf (stderr, "\n TG Hex = 0x%06X", tghex);
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
// if (i == 3) fprintf (stderr, "\n ");
// }
// tghex = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
// //fprintf (stderr, "\n TG Hex = 0x%06X", tghex);
// state->dmr_mfid = 0x10;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
// //nullify any previous TIII data (bugfix for bad assignments or system type switching)
// sprintf(state->dmr_site_parms, "%s", "");
fprintf (stderr, "%s", KNRM);
// fprintf (stderr, "%s", KNRM);
//Skip tuning group calls if group calls are disabled
if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
// //Skip tuning group calls if group calls are disabled
// if (opts->trunk_tune_group_calls == 0) goto SKIPCAP;
//don't tune if currently a vc on the current channel
if ( (time(NULL) - state->last_vc_sync_time > 2) )
{
for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
{
char mode[8]; //allow, block, digital, enc, etc
// //don't tune if currently a vc on the current channel
// if ( (time(NULL) - state->last_vc_sync_time > 2) )
// {
// for (j = 0; j < 8; j++) //go through the channels stored looking for active ones to tune to
// {
// char mode[8]; //allow, block, digital, enc, etc
//if we are using allow/whitelist mode, then write 'B' to mode for block
//comparison below will look for an 'A' to write to mode if it is allowed
if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
// //if we are using allow/whitelist mode, then write 'B' to mode for block
// //comparison below will look for an 'A' to write to mode if it is allowed
// if (opts->trunk_use_allow_list == 1) sprintf (mode, "%s", "B");
for (int i = 0; i < state->group_tally; i++)
{
if (state->group_array[i].groupNumber == t_tg[j])
{
fprintf (stderr, " [%s]", state->group_array[i].groupName);
strcpy (mode, state->group_array[i].groupMode);
}
}
// for (int i = 0; i < state->group_tally; i++)
// {
// if (state->group_array[i].groupNumber == t_tg[j])
// {
// fprintf (stderr, " [%s]", state->group_array[i].groupName);
// strcpy (mode, state->group_array[i].groupMode);
// }
// }
//no more 0 reporting, that was some bad code that caused that issue
//without priority, this will tune the first one it finds (if group isn't blocked)
if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
{
if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
{
//RIGCTL
if (opts->use_rigctl == 1)
{
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
j = 11; //break loop
}
// //no more 0 reporting, that was some bad code that caused that issue
// //without priority, this will tune the first one it finds (if group isn't blocked)
// if (t_tg[j] != 0 && state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "B") != 0) && (strcmp(mode, "DE") != 0))
// {
// if (state->trunk_chan_map[j+1] != 0) //if we have a valid frequency
// {
// //RIGCTL
// if (opts->use_rigctl == 1)
// {
// if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
// SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[j+1]);
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
// opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
// j = 11; //break loop
// }
//rtl_udp
else if (opts->audio_in_type == 3)
{
rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
opts->p25_is_tuned = 1;
j = 11; //break loop
}
// //rtl_udp
// else if (opts->audio_in_type == 3)
// {
// rtl_udp_tune (opts, state, state->trunk_chan_map[j+1]);
// state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[j+1];
// opts->p25_is_tuned = 1;
// j = 11; //break loop
// }
}
}
// }
// }
}
}
// }
// }
}
SKIPCAP: ; //do nothing
}
// }
// SKIPCAP: ; //do nothing
// }
//Connect+ Section
if (csbk_fid == 0x06)
@@ -888,67 +1085,6 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
}
//upon further examination, opcodes 6 and C (12) do not appear to be a channel grants or tlcs,
//it is present in Connect+, but its purpose isn't entirely clear
//DSDPlus only regards it as a 'CSBK [LB=1 CSBKO=6 (?) FID=06 v1=115213 v2=10488576 v3=0]
//unsure of what the v1 v2 v3 fields specify
// if (csbk_o == 0x06 || csbk_o == 0x0C)
if (csbk_o != 0x01 && csbk_o != 0x03)
{
uint32_t v1 = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
uint32_t v2 = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
uint32_t v3 = ( (cs_pdu[7] << 16) + (cs_pdu[8] << 8) + cs_pdu[9] );
// debug print
// initial line break
// fprintf (stderr, "\n");
// fprintf (stderr, "%s", KYEL);
// fprintf (stderr, " Connect Plus CSBK 0x%X\n", csbk_o);
// fprintf (stderr, " v1(%d), v2(%d), v3(%d)",v1, v2, v3);
// state->dmr_mfid = 0x06;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf(state->dmr_branding_sub, "Con+ ");
}
//the validity of these last three csbk opcodes cannot be confirmed
//I recall making these based on observation and speculation long ago,
//but cannot verify the accuracy of them now, so they will remain disabled
//they offer no particular interest to trunking/listening
// if (csbk_o == 0x11)
// {
// //initial line break
// fprintf (stderr, "\n");
// fprintf (stderr, "%s", KYEL);
// fprintf (stderr, " Connect Plus Registration Request");
// state->dmr_mfid = 0x06;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf(state->dmr_branding_sub, "Con+ ");
// }
// if (csbk_o == 0x12)
// {
// //initial line break
// fprintf (stderr, "\n");
// fprintf (stderr, "%s", KYEL);
// fprintf (stderr, " Connect Plus Registration Response");
// state->dmr_mfid = 0x06;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf(state->dmr_branding_sub, "Con+ ");
// }
// if (csbk_o == 0x18)
// {
// //initial line break
// fprintf (stderr, "\n");
// fprintf (stderr, "%s", KYEL);
// fprintf (stderr, " Connect Plus Talkgroup Affiliation");
// state->dmr_mfid = 0x06;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf(state->dmr_branding_sub, "Con+ ");
// }
fprintf (stderr, "%s", KNRM);
}

View File

@@ -56,6 +56,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[i];
}
else state->dmr_stereo_payload[i] = dibit;
cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
@@ -103,6 +104,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[i+12];
}
else state->dmr_stereo_payload[i+12] = dibit;
info[2*i] = (1 & (dibit >> 1)); // bit 1
info[(2*i)+1] = (1 & dibit); // bit 0
}
@@ -118,6 +120,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[61];
}
else state->dmr_stereo_payload[61] = dibit;
SlotType[0] = (1 & (dibit >> 1)); // bit 1
SlotType[1] = (1 & dibit); // bit 0
@@ -132,6 +135,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[62];
}
else state->dmr_stereo_payload[62] = dibit;
SlotType[2] = (1 & (dibit >> 1)); // bit 1
SlotType[3] = (1 & dibit); // bit 0
@@ -146,6 +150,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[63];
}
else state->dmr_stereo_payload[63] = dibit;
SlotType[4] = (1 & (dibit >> 1)); // bit 1
SlotType[5] = (1 & dibit); // bit 0
@@ -160,6 +165,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[64];
}
else state->dmr_stereo_payload[64] = dibit;
SlotType[6] = (1 & (dibit >> 1)); // bit 1
SlotType[7] = (1 & dibit); // bit 0
@@ -175,6 +181,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[65];
}
else state->dmr_stereo_payload[65] = dibit;
SlotType[8] = (1 & (dibit >> 1)); // bit 1
SlotType[9] = (1 & dibit); // bit 0
@@ -191,6 +198,8 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
{
dibit = (int)state->dmr_stereo_payload[i+66];
}
else state->dmr_stereo_payload[i+66] = dibit;
syncdata[2*i] = (1 & (dibit >> 1)); // bit 1
syncdata[(2*i)+1] = (1 & dibit); // bit 0
sync[i] = (dibit | 1) + 48;
@@ -236,6 +245,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
if (state->dmr_stereo == 0)
{
dibit = getDibit(opts, state);
state->dmr_stereo_payload[i+90] = dibit;
}
if (state->dmr_stereo == 1)
{
@@ -277,6 +287,7 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
if (state->dmr_stereo == 0)
{
dibit = getDibit(opts, state);
state->dmr_stereo_payload[i+95] = dibit;
}
if (state->dmr_stereo == 1)
@@ -288,10 +299,11 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
info[(2*i) + 99] = (1 & dibit); // bit 0
}
dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
//don't run on MS Reverse Channel Data
if (state->dmr_ms_rc == 0) dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
//don't run cach on simplex or mono
if (state->dmr_ms_mode == 0 || opts->dmr_mono == 0)
if (state->dmr_ms_mode == 0 && opts->dmr_mono == 0)
{
cach_err = dmr_cach (opts, state, cachdata);
}

View File

@@ -9,9 +9,9 @@
* 2022-12 DSD-FME Florida Man Edition
*-----------------------------------------------------------------------------*/
//TODO: CRC9 on confirmed data blocks; CRC32 on completed data sf;
//TODO: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC
//TODO: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key
//WIP: CRC9 on confirmed data blocks; CRC32 on completed data sf;
//WIP: Reverse Channel Signalling - RC single burst BPTC/7-bit CRC
//WIP: Single Burst Embedded LC - Non-RC single burst LC - Look for Late Entry Alg/Key
#include "dsd.h"
@@ -26,6 +26,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
uint8_t slot = state->currentslot;
uint8_t block = state->data_block_counter[slot];
//confirmed data
uint8_t dbsn = 0; //data block serial number for confirmed data blocks
uint8_t blockcounter = 0; //local block count
uint8_t confdatabits[250]; //array to reshuffle conf data block bits into sequence for crc9 check
memset (confdatabits, 0, sizeof(confdatabits));
//BPTC 196x96 Specific
uint8_t BPTCDeInteleavedData[196];
uint8_t BPTCDmrDataBit[96];
@@ -45,9 +51,11 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
uint8_t R[3];
uint8_t BPTCReservedBits = 0;
uint8_t is_ras = 0;
uint8_t crc_original_validity = 0;
uint32_t crcmask = 0;
uint8_t crclen = 0;
uint8_t crclen = 0;
uint8_t is_bptc = 0;
uint8_t is_trellis = 0;
@@ -108,32 +116,31 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " DATA");
break;
//TODO - 1/2 0x0F0 - 3/4 0x1FF - Rate 1 0x10F
//going to set crclen and mask according to confirmed data here,
//use block assmebler to carry out completed message crc
case 0x07: //1/2 Rate Data
is_bptc = 1;
crclen = 9; //confirmed data only
crcmask = 0x0F0;
pdu_len = 12; //12 bytes unconfirmed
sprintf(state->fsubtype, " R12U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 10;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R12C ");
}
sprintf(state->fsubtype, " R12D ");
break;
case 0x08: //3/4 Rate Data
is_trellis = 1;
crclen = 9; //confirmed data only
crcmask = 0x1FF;
pdu_len = 18; //18 bytes unconfirmed
sprintf(state->fsubtype, " R34U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 16;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R34C ");
}
sprintf(state->fsubtype, " R34D ");
break;
case 0x09: //Idle
//pseudo-random data fill, no need to do anything with this
@@ -141,10 +148,16 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
break;
case 0x0A: //1 Rate Data
crclen = 9; //confirmed data only
crcmask = 0x1FF;
crcmask = 0x10F;
is_full = 1;
pdu_len = 25; //196 bits - 24.5 bytes
sprintf(state->fsubtype, " R_1D ");
pdu_len = 25; //196 bits - 24.5 bytes
sprintf(state->fsubtype, " R_1U ");
if (state->data_conf_data[slot] == 1)
{
pdu_len = 23;
pdu_start = 2; //start at plus two when assembling
sprintf(state->fsubtype, " R_1C ");
}
break;
case 0x0B: //Unified Data
is_bptc = 1;
@@ -153,13 +166,21 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
pdu_len = 12; //12 bytes
sprintf(state->fsubtype, " UDAT ");
break;
//special types (not real data 'sync' bursts)
case 0xEB: //Embedded Signalling
crclen = 5;
is_emb = 1;
pdu_len = 9;
break;
default:
//Slot Type FEC should catch this so we never see it,
//but if it doesn't, then we can still dump the entire 'packet'
//treat like rate 1 unconfirmed data
is_full = 1;
pdu_len = 25; //196 bits - 24.5 bytes
sprintf(state->fsubtype, " _UNK ");
break;
}
@@ -168,6 +189,26 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
{
if (state->dmr_ms_mode == 0) fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code);
fprintf(stderr, "|%s", state->fsubtype);
//'DSP' output to file
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 98 ", slot+1); //'98' is CACH designation value
for (i = 0; i < 6; i++) //3 byte CACH
{
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", cach_byte);
}
fprintf (pFile, "\n%d %02X ", slot+1, databurst); //use hex value of current data burst type
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
}
//Most Data Sync Burst types will use the bptc 196x96
@@ -184,7 +225,11 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
IrrecoverableErrors = BPTC_196x96_Extract_Data(BPTCDeInteleavedData, BPTCDmrDataBit, R);
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08);
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x04);
//debug print
//fprintf (stderr, " RAS? %X - %d %d %d", BPTCReservedBits, R[0], R[1], R[2]);
/* Convert the 96 bits BPTC data into 12 bytes */
k = 0;
@@ -213,10 +258,39 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
/* Check/correct the BPTC data and compute the Reed-Solomon (12,9) CRC */
if (is_lc) CRCCorrect = ComputeAndCorrectFullLinkControlCrc(BPTCDmrDataByte, &CRCComputed, crcmask);
//TODO: run CRC9 on confirmed 1/2 data blocks
else if (state->data_conf_data[slot] == 1)
//set CRC to correct on unconfirmed 1/2 data blocks (for reporting due to no CRC available on these)
else if (state->data_conf_data[slot] == 0 && databurst == 0x7)
{
//run CRC on individual blocks according to type and validate each individual block
CRCComputed = 0;
CRCExtracted = 0;
CRCCorrect = 1;
}
//set CRC to correct on proprietary data header blocks (unsure if p_head data has valid crcs,
//may be ras enabled, manufacturer specific, or none, currently unknown, but possibly RAS on samples I have)
// else if (state->data_p_head[slot] == 1 && databurst == 0x06) CRCCorrect = 1;
//run CRC9 on intermediate and last 1/2 confirmed data blocks
else if (state->data_conf_data[slot] == 1 && databurst == 0x7)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&BPTCDmrDataBit[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the BPTCDmrDataBit array into confdatabits, just for CRC9 check
//need to find a sample to confirm this
for(i = 0; i < 80; i++) confdatabits[i] = BPTCDmrDataBit[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 80] = BPTCDmrDataBit[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 87);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else state->data_block_crc_valid[slot][blockcounter] = 0;
}
//run CCITT on other data forms
@@ -225,6 +299,20 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
else CRCCorrect = 0;
}
//set the 'RAS Flag', if no irrecoverable errors but bad crc, only when enabled by user (to prevent a lot of bad data CSBKs)
if (opts->aggressive_framesync == 0 && CRCCorrect == 0 && IrrecoverableErrors == 0 && BPTCReservedBits == 4) is_ras = 1; //!=0, or == 0x4, or just R[2] == 1
//make sure the system type isn't Hytera, but could just be bad decodes on bad sample
if (BPTCDmrDataByte[1] == 0x68) is_ras = 0;
//if this is a RAS system, set the CRC to okay if irrecoverable errors is okay
//if we don't do this, then we can't view some data (CSBKs on RAS enabled systems)
if (is_ras == 1)
{
crc_original_validity = CRCCorrect;
CRCCorrect = 1;
}
if (databurst == 0x04 || databurst == 0x06) //MBC Header, Data Header
@@ -295,11 +383,7 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
IrrecoverableErrors = BPTC_128x77_Extract_Data(BptcDataMatrix, LC_DataBit);
/* Reconstitute the 5 bit CRC */
CRCExtracted = (LC_DataBit[72] & 1) << 4;
CRCExtracted |= (LC_DataBit[73] & 1) << 3;
CRCExtracted |= (LC_DataBit[74] & 1) << 2;
CRCExtracted |= (LC_DataBit[75] & 1) << 1;
CRCExtracted |= (LC_DataBit[76] & 1) << 0;
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&LC_DataBit[72], 5);
/* Compute the 5 bit CRC */
CRCComputed = ComputeCrc5Bit(LC_DataBit);
@@ -348,6 +432,50 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
}
for(i = 0, j = 0; i < 18; i++, j+=8)
{
DMR_PDU_bits[j + 0] = (TrellisReturn[i] >> 7) & 0x01;
DMR_PDU_bits[j + 1] = (TrellisReturn[i] >> 6) & 0x01;
DMR_PDU_bits[j + 2] = (TrellisReturn[i] >> 5) & 0x01;
DMR_PDU_bits[j + 3] = (TrellisReturn[i] >> 4) & 0x01;
DMR_PDU_bits[j + 4] = (TrellisReturn[i] >> 3) & 0x01;
DMR_PDU_bits[j + 5] = (TrellisReturn[i] >> 2) & 0x01;
DMR_PDU_bits[j + 6] = (TrellisReturn[i] >> 1) & 0x01;
DMR_PDU_bits[j + 7] = (TrellisReturn[i] >> 0) & 0x01;
}
//set CRC to correct on unconfirmed 3/4 data blocks (for reporting due to no CRC available on these)
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
//run CRC9 on intermediate and last 3/4 data blocks
else if (state->data_conf_data[slot] == 1)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&DMR_PDU_bits[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the DMR_PDU_bits array into confdatabits, just for CRC9 check
//confirmed working now!
for(i = 0; i < 128; i++) confdatabits[i] = DMR_PDU_bits[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 128] = DMR_PDU_bits[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 135);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else
{
IrrecoverableErrors = 9; //set as a shim since the trellis decoder is a pain to fix
state->data_block_crc_valid[slot][blockcounter] = 0;
}
}
//reorganize the DMR_PDU_bits into PDU friendly format (minus the dbsn and crc9)
memset (DMR_PDU_bits, 0, sizeof(DMR_PDU_bits));
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
{
DMR_PDU_bits[j + 0] = (TrellisReturn[i+pdu_start] >> 7) & 0x01;
@@ -360,17 +488,13 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
DMR_PDU_bits[j + 7] = (TrellisReturn[i+pdu_start] >> 0) & 0x01;
}
//TODO: run CRC9 on confirmed 3/4 data blocks
}
if (is_full) //Rate 1 Data
{
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0;
//TODO: run CRC9 on confirmed data
IrrecoverableErrors = 0; //implicit, since there is no encoding
for (i = 0; i < 24; i++)
{
@@ -381,6 +505,32 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
DMR_PDU[25] = (uint8_t)ConvertBitIntoBytes(&info[192], 4);
DMR_PDU[25] = DMR_PDU[25] << 4;
//set CRC to correct on unconfirmed 1 rate data blocks (for reporting due to no CRC available on these)
if (state->data_conf_data[slot] == 0) CRCCorrect = 1;
//run CRC9 on intermediate and last 1 rate data blocks
else if (state->data_conf_data[slot] == 1)
{
blockcounter = state->data_block_counter[slot]; //current block number according to the counter
dbsn = (uint32_t)ConvertBitIntoBytes(&info[0], 7) + 1; //recover data block serial number
CRCExtracted = (uint32_t)ConvertBitIntoBytes(&info[7], 9); //extract CRC from data
CRCExtracted = CRCExtracted ^ crcmask;
//reorganize the info bit array into confdatabits, just for CRC9 check
//unconfirmed, haven't seen any samples with rate 1 data
for(i = 0; i < 176; i++) confdatabits[i] = info[i + 16];
for(i = 0; i < 7; i++) confdatabits[i + 176] = info[i];
CRCComputed = ComputeCrc9Bit(confdatabits, 183);
if (CRCExtracted == CRCComputed)
{
CRCCorrect = 1;
state->data_block_crc_valid[slot][blockcounter] = 1;
}
else state->data_block_crc_valid[slot][blockcounter] = 0;
}
//copy info to dmr_pdu_bits
memcpy(DMR_PDU_bits, info, sizeof(DMR_PDU_bits));
@@ -399,13 +549,12 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
if (databurst == 0x06) dmr_dheader (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
if (databurst == 0x07) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //1/2 Rate Data
if (databurst == 0x08) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //3/4 Rate Data
//if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data - Disabled until further testing can be done
if (databurst == 0x0A) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Full Rate Data
//is unified data handled like normal data, or control signalling data?
//my best understanding is that unified data carries supplimentary MS data on TIII systems, not control signalling
if (databurst == 0x0B) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 1); //Unified Data
//if (databurst == 0x0B) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors);
//control signalling types (CSBK, MBC, UDT)
//control signalling types (CSBK, MBC)
if (databurst == 0x03) dmr_cspdu (opts, state, DMR_PDU_bits, DMR_PDU, CRCCorrect, IrrecoverableErrors);
//both MBC header and MBC continuation will go to the block_assembler - type 2, and then to dmr_cspdu
@@ -416,6 +565,44 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
}
if (databurst == 0x05) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
//set the original CRCCorrect back to its original value if the RAS flag was tripped
if (is_ras == 1) CRCCorrect = crc_original_validity;
//start printing relevant fec/crc/ras messages, don't print on idle or MBC continuation blocks (handled in dmr_block.c)
if (CRCCorrect == 1 && databurst != 0x09 && databurst != 0x05) ; //fprintf(stderr, "(CRC OK)");
if (IrrecoverableErrors == 0 && CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
{
fprintf (stderr, "%s", KYEL);
fprintf(stderr, " (FEC OK)");
fprintf (stderr, "%s", KNRM);
}
if (IrrecoverableErrors != 0 && databurst != 0x09 && databurst != 0x05)
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " (FEC ERR)");
fprintf (stderr, "%s", KNRM);
}
//print whether or not the 'RAS Field' bits are set to indicate RAS enabled (to be verified)
if (is_ras == 1)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " -RAS ");
//the value of this field seems to always, or usually, be 4, or just R[2] bit is set
if (opts->payload == 1) fprintf (stderr, "%X ", BPTCReservedBits);
fprintf (stderr, "%s", KNRM);
}
if (CRCCorrect == 0 && databurst != 0x09 && databurst != 0x05)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR) ");
fprintf (stderr, "%s", KNRM);
}
//print the unified PDU format here, if not slot idle
if (opts->payload == 1 && databurst != 0x09)
{
@@ -427,20 +614,31 @@ void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196
fprintf (stderr, "[%02X]", DMR_PDU[i]);
}
//debug print
// if (dbsn) fprintf (stderr, " SN %X", dbsn);
// fprintf (stderr, " CRC - EXT %X CMP %X", CRCExtracted, CRCComputed);
fprintf (stderr, "%s", KNRM);
// fprintf (stderr, "%s", KCYN);
// fprintf (stderr, "\n Hex to Ascii - ");
// for (i = 0; i < 12; i++)
// {
// if (DMR_PDU[i] <= 0x7E && DMR_PDU[i] >=0x20)
// {
// fprintf (stderr, "%c", DMR_PDU[i]);
// }
// else fprintf (stderr, ".");
// }
//short data - DD_HEAD, SP_HEAD or R_HEAD (Might do on TMS as well)
if ( (state->data_header_format[slot] & 0xF) == 0xD )
{
fprintf (stderr, "%s", KCYN);
fprintf (stderr, "\n Hex to Ascii - ");
for (i = 0; i < pdu_len; i++)
{
if (DMR_PDU[i] <= 0x7E && DMR_PDU[i] >=0x20)
{
fprintf (stderr, "%c", DMR_PDU[i]);
}
else fprintf (stderr, ".");
}
fprintf (stderr,"%s", KNRM);
}
fprintf (stderr,"%s", KNRM);
}
}

View File

@@ -25,11 +25,13 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
uint8_t so = 0;
uint32_t target = 0;
uint32_t source = 0;
uint8_t capsite = 0;
int restchannel = -1;
int is_cap_plus = 0;
int is_alias = 0;
int is_gps = 0;
uint8_t slot = state->currentslot;
uint8_t unk = 0; //flag for unknown FLCO + FID combo
pf = (uint8_t)(lc_bits[0]); //Protect Flag
@@ -40,48 +42,106 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
//check protect flag
if (pf == 1)
{
if (type == 1) fprintf (stderr, "%s \n", KRED);
if (type == 2) fprintf (stderr, "%s \n", KRED);
if (type == 3) fprintf (stderr, "%s", KRED);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " Protected LC ");
goto END_FLCO;
}
//look for Cap+ on VLC header, then set source and/or rest channel appropriately
if (type == 1 && fid == 0x10 && flco == 0x04)
if (IrrecoverableErrors == 0 && type == 1 && fid == 0x10 && (flco == 0x04 || flco == 0x07) ) //0x07 appears to be a cap+ txi private call
{
is_cap_plus = 1;
restchannel = (int)ConvertBitIntoBytes(&lc_bits[48], 8);
capsite = (uint8_t)ConvertBitIntoBytes(&lc_bits[48], 4); //can't verify, just speculating
restchannel = (int)ConvertBitIntoBytes(&lc_bits[52], 4); //was 48,8
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
}
if (IrrecoverableErrors == 0)
{
if (slot == 0) state->dmr_flco = flco;
else state->dmr_flcoR = flco;
//Embedded Talker Alias Header Only (format and len storage)
if (type == 3 && flco == 0x04)
if (fid == 0 && type == 3 && flco == 0x04)
{
dmr_embedded_alias_header(opts, state, lc_bits);
}
//Embedded Talker Alias Header (continuation) and Blocks
if (type == 3 && flco > 0x3 && flco < 0x08)
if (fid == 0 && type == 3 && flco > 0x3 && flco < 0x08)
{
is_alias = 1;
dmr_embedded_alias_blocks(opts, state, lc_bits);
}
//Embedded GPS
if (type == 3 && flco == 0x08)
if (fid == 0 && type == 3 && flco == 0x08)
{
is_gps = 1;
if (fid == 0) dmr_embedded_gps(opts, state, lc_bits); //issues with fid 0x10 and flco 0x08
dmr_embedded_gps(opts, state, lc_bits);
}
//NOTE: fid 0x10 and flco 0x08 produces a lot of 'zero' lat or lon values, I don't believe this is embedded gps
//Unknown CapMax/Moto Things
if (fid == 0x10 && (flco == 0x08 || flco == 0x28))
{
//NOTE: fid 0x10 and flco 0x08 (emb) produces a lot of 'zero' bytes
//this has been observed to happen often on CapMax systems, so I believe it could be some CapMax 'thing'
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <-- have the enc bit set on svc, but these calls aren't enc?
//is this an encrypted embedded link control?
else
{
fprintf (stderr, "%s", KGRN);
fprintf (stderr, " Slot %d Unknown EMB LC - FLCO=0x%02X FID=0x%02X SVC=0x%02X ", slot+1, flco, fid, so);
fprintf (stderr, "%s", KNRM);
}
//Unknown Link Control - FLCO=0x08 FID=0x10 SVC=0xC1 or FLCO=0x08 FID=0x10 SVC=0xC0 <- probably no SVC bits in the lc
//flco 0x28 has also been observed lately but the tg and src values don't match
//another flco 0x10 does seem to match, so is probably capmax group call flco
if (type == 1) fprintf (stderr, "%s \n", KCYN);
if (type == 2) fprintf (stderr, "%s \n", KCYN);
if (type == 3) fprintf (stderr, "%s", KCYN);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " Motorola");
unk = 1;
goto END_FLCO;
}
//7.1.1.1 Terminator Data Link Control PDU - ETSI TS 102 361-3 V1.2.1 (2013-07)
if (type == 2 && flco == 0x30)
{
fprintf (stderr, "%s \n", KRED);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " Data Terminator (TD_LC)");
fprintf (stderr, "%s ", KNRM);
goto END_FLCO;
}
//Unknown Tait Things
if (fid == 0x58)
{
//NOTE: fid 0x58 (tait) had a single flco 0x06 emb observed, but without the other blocks (4,5,7) for an alias
//will need to observe this one, or just remove it from the list, going to isolate tait lc for now
if (type == 1) fprintf (stderr, "%s \n", KCYN);
if (type == 2) fprintf (stderr, "%s \n", KCYN);
if (type == 3) fprintf (stderr, "%s", KCYN);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " Tait");
unk = 1;
goto END_FLCO;
}
//unknown other manufacturer or OTA ENC, etc.
if (fid != 0 && fid != 0x68 && fid != 0x10) //removed tait from the list
{
if (type == 1) fprintf (stderr, "%s \n", KYEL);
if (type == 2) fprintf (stderr, "%s \n", KYEL);
if (type == 3) fprintf (stderr, "%s", KYEL);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " Unknown LC ");
unk = 1;
goto END_FLCO;
}
}
@@ -131,6 +191,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
// state->lastsrc = 0;
state->payload_algid = 0;
state->payload_mi = 0;
state->payload_keyid = 0;
}
if (state->currentslot == 1)
{
@@ -140,6 +201,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
// state->lastsrcR = 0;
state->payload_algidR = 0;
state->payload_miR = 0;
state->payload_keyidR = 0;
}
}
@@ -162,14 +224,32 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf(stderr, "TGT=%u SRC=%u ", target, source);
if (opts->payload == 1) fprintf(stderr, "FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
if (flco == 3) //UU_V_Ch_Usr
//0x04 and 0x05 on a TLC seem to indicate a Cap + Private Call Terminator (perhaps one for each MS)
//0x07 on a VLC seems to indicate a Cap+ Private Call Header
//0x23 on the Embedded Voice Burst Sync seems to indicate a Cap+ Private Call in progress
if (flco == 0x4 || flco == 0x5 || flco == 0x7 || flco == 0x23) //Cap+ Things
{
sprintf (state->call_string[slot], " Private");
sprintf (state->call_string[slot], " Cap+");
fprintf (stderr, "Cap+ ");
if (flco == 0x4)
{
strcat (state->call_string[slot], " Grp");
fprintf (stderr, "Group ");
}
else
{
strcat (state->call_string[slot], " Pri");
fprintf (stderr, "Private ");
}
}
else if (flco == 0x3) //UU_V_Ch_Usr
{
sprintf (state->call_string[slot], " Private ");
fprintf (stderr, "Private ");
}
}
else //Grp_V_Ch_Usr
{
sprintf (state->call_string[slot], " Group");
sprintf (state->call_string[slot], " Group ");
fprintf (stderr, "Group ");
}
@@ -206,7 +286,7 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
{
//REMUS! Uncomment Line Below if desired
// strcat (state->call_string[slot], " RES");
fprintf(stderr, "Reserved=%d ", (so & 0x30) >> 4);
fprintf(stderr, "RS%d ", (so & 0x30) >> 4);
}
}
if(so & 0x08)
@@ -251,10 +331,6 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
fprintf(stderr, "Call ");
fprintf (stderr, "%s", KRED);
if (CRCCorrect == 1) ; //CRCCorrect 1 is good, else is bad CRC; no print on good
else if(IrrecoverableErrors == 0) fprintf(stderr, "(FEC/RAS)");
else fprintf(stderr, "(FEC/CRC ERR)");
//check Cap+ rest channel info if available and good fec
if (is_cap_plus == 1)
@@ -299,6 +375,24 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
}
END_FLCO:
if (unk == 1 || pf == 1)
{
// fprintf(stderr, " FLCO=0x%02X FID=0x%02X SVC=0x%02X ", flco, fid, so);
fprintf(stderr, " FLCO=0x%02X FID=0x%02X ", flco, fid); //not all LC PDUs contain SVC bits (see TD_LC)
fprintf (stderr, "%s", KNRM);
}
if(IrrecoverableErrors != 0)
{
if (type != 3) fprintf (stderr, "\n");
fprintf (stderr, "%s", KRED);
fprintf (stderr, " SLOT %d", state->currentslot+1);
fprintf (stderr, " FLCO FEC ERR ");
fprintf (stderr, "%s", KNRM);
}
}
//externalized dmr cach - tact and slco fragment handling
@@ -553,7 +647,9 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
uint8_t con_netid = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 8);
uint8_t con_siteid = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 8);
//Cap+
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8);
uint8_t capsite = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 4); //can't verify, just speculating
uint8_t restchannel = (uint8_t)ConvertBitIntoBytes(&slco_bits[16], 4); //was 12,8
uint8_t cap_reserved = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //unknown if any significant value?
//initial line break
fprintf (stderr, "\n");
@@ -602,18 +698,20 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
fprintf (stderr, " SLCO Activity Update TS1: %X Hash: %02X TS2: %X Hash: %02X", ts1_act, ts1_hash, ts2_act, ts2_hash); //102 361-2 7.1.3.2
else if (slco == 0x9)
{
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
//remove all setting of branding/sub from SLCO, can cause false positives even with seeming good CRC
// state->dmr_mfid = 0x10;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
}
else if (slco == 0xA)
{
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
// state->dmr_mfid = 0x10;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf (state->dmr_branding_sub, "%s", "Con+ ");
fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
sprintf (state->dmr_site_parms, "%d-%d ", con_netid, con_siteid);
@@ -627,11 +725,11 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
else if (slco == 0xF)
{
state->dmr_mfid = 0x10;
sprintf (state->dmr_branding, "%s", "Motorola");
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
fprintf (stderr, " SLCO Capacity Plus Rest Channel %d", restchannel);
state->dmr_rest_channel = restchannel;
// state->dmr_mfid = 0x10;
// sprintf (state->dmr_branding, "%s", "Motorola");
// sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
fprintf (stderr, " SLCO Capacity Plus Site: %d - Rest Channel %d - RS: %02X", capsite+1, restchannel, cap_reserved);
// state->dmr_rest_channel = restchannel; //test without, may work better
//assign to cc freq if available
if (state->trunk_chan_map[restchannel] != 0)
{
@@ -639,7 +737,7 @@ void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
}
//nullify any previous TIII data (bugfix for bad assignments or system type switching)
sprintf(state->dmr_site_parms, "%s", "");
// sprintf(state->dmr_site_parms, "%s", "");
}
else fprintf (stderr, " SLCO Unknown - %d ", slco);

View File

@@ -137,3 +137,157 @@ void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
state->payload_miP = 0;
}
//handle Single Burst (Voice Burst F) or Reverse Channel Signalling
//(Embedded or Dedicated Outbound, not Stand Alone (MS sourced) or Direct Mode)
//MS Sourced or Direct Mode probably would be handled poorly by the demodulator
void dmr_sbrc (dsd_opts * opts, dsd_state * state, uint8_t power)
{
int i;
uint8_t slot = state->currentslot;
uint8_t sbrc_interleaved[32];
uint8_t sbrc_return[32];
memset (sbrc_interleaved, 0, sizeof(sbrc_interleaved));
memset (sbrc_return, 0, sizeof(sbrc_return));
uint32_t irr_err = 0;
uint32_t sbrc_hex = 0;
uint16_t crc_extracted = 7777;
uint16_t crc_computed = 9999;
uint8_t crc_okay = 0;
// 9.3.2 Pre-emption and power control Indicator (PI)
// 0 - The embedded signalling carries information associated to the same logical channel or the Null embedded message
// 1 - The embedded signalling carries RC information associated to the other logical channel
for(i = 0; i < 32; i++) sbrc_interleaved[i] = state->dmr_embedded_signalling[slot][5][i + 8];
//power == 0 should be single burst
if (power == 0) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 0);
//power == 1 should be reverse channel -- still need to check the interleave inside of BPTC
if (power == 1) irr_err = BPTC_16x2_Extract_Data(sbrc_interleaved, sbrc_return, 1);
//bad emb burst, never set a valid power indicator value (probably 9)
if (power > 1) goto SBRC_END;
//RC Channel CRC 7 Mask = 0x7A; CRC bits are used as privacy indicators on
//Single Voice Burst F (see below), other moto values seem to exist there as well
//unknown what the other values are (see Cap+ 0x313)
if (power == 1) //RC
{
crc_extracted = 0;
for (i = 0; i < 7; i++)
{
crc_extracted = crc_extracted << 1;
crc_extracted = crc_extracted | sbrc_return[i+4];
}
crc_extracted = crc_extracted ^ 0x7A;
crc_computed = crc7((uint8_t *) sbrc_return, 11);
if (crc_extracted == crc_computed) crc_okay = 1;
}
else crc_okay = 1; //SB
if (opts->payload == 1) //hide the sb/rc behind the payload printer, won't be useful to most people right now
{
fprintf (stderr, "\n %s", KCYN);
if (power == 0) fprintf (stderr, " SB: ");
if (power == 1) fprintf (stderr, " RC: ");
for(i = 0; i < 11; i++)
{
sbrc_hex = sbrc_hex << 1;
sbrc_hex |= sbrc_return[i] & 1; //sbrc_return
fprintf (stderr, "%d", sbrc_return[i]);
}
fprintf (stderr, " - %03X", sbrc_hex);
fprintf (stderr, "%s", KNRM);
if (crc_okay == 0)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " (CRC ERR)");
fprintf (stderr, "%s", KNRM);
if (opts->payload == 1) fprintf (stderr, " CRC EXT %02X, CRC CMP %02X", crc_extracted, crc_computed);
}
}
//sbrc_hex value of 0x313 seems to be some Cap+ Thing,
//also observed 0x643 on another cap+ system (site id, status? something?)
//I've observed it in the Private Cap+ TXI calls as well
//there also seems to be a correlation between the SVC bits for TXI (reserved=3) and these extra cap+ values
uint8_t sbrc_opcode = sbrc_hex;
uint8_t alg = sbrc_hex & 3;
uint16_t key = (sbrc_hex >> 3) & 0xFF;
if (opts->payload == 1)
{
if (irr_err != 0) fprintf (stderr, "%s (FEC ERR) %d %s", KRED, irr_err, KNRM);
if (irr_err == 0)
{
if (sbrc_hex == 0) ; //NULL
else if (sbrc_hex == 0x313)
{
//Cap+ Thing? Observed On Cap+ Systems
// fprintf (stderr, " Cap+ Thing?");
}
else
{
if (slot == 0)
{
//key and alg only present SOME times, not all,
//also, intermixed with other signalling
//needs more study first!
if (state->dmr_so & 0x40 && key != 0 && state->payload_keyid == 0)
{
if (opts->payload == 1)
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 1");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
}
//needs more study before assignment
//state->payload_keyid = key;
//state->payload_algid = alg + 0x20; //assuming DMRA approved alg values (moto patent)
}
}
if (slot == 1)
{
if (state->dmr_soR & 0x40 && key != 0 && state->payload_keyidR == 0)
{
if (opts->payload == 1)
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 2");
fprintf (stderr, " DMR LE SB ALG ID: %X KEY ID: %0X", alg + 0x20, key);
fprintf (stderr, "%s ", KNRM);
}
//needs more study before assignment
//state->payload_keyidR = key;
//state->payload_algidR = alg + 0x20; //assuming DMRA approved alg values (moto patent)
}
}
}
}
}
SBRC_END:
//'DSP' output to file -- only RC, or RC and SB?
if (power == 1 && opts->use_dsp_output == 1 && sbrc_hex != 0) //if not NULL
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 99 ", slot+1); //'99' is RC designation value
int k = 0;
for (i = 0; i < 24; i++) //12 bytes, SB or RC
{
//check to see if k++ starts at zero, or at 1
int sbrc_nib = (state->dmr_embedded_signalling[slot][5][k++] << 3) | (state->dmr_embedded_signalling[slot][5][k++] << 2) | (state->dmr_embedded_signalling[slot][5][k++] << 1) | (state->dmr_embedded_signalling[slot][5][k++] << 0);
fprintf (pFile, "%X", sbrc_nib);
}
fclose (pFile);
}
}

View File

@@ -50,6 +50,11 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
uint8_t internalslot;
uint8_t vc;
//assign as nonsensical numbers
uint8_t cc = 25;
uint8_t power = 9; //power and pre-emption indicator
uint8_t lcss = 9;
//dummy bits to pass to dburst for link control
uint8_t dummy_bits[196];
memset (dummy_bits, 0, sizeof (dummy_bits));
@@ -87,7 +92,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 12; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
cachdata[i] = dibit;
state->dmr_stereo_payload[i] = dibit;
@@ -119,7 +124,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 36; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i+12] = dibit;
@@ -144,7 +149,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 18; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i+48] = dibit;
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
@@ -171,7 +176,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
sync[i] = (dibit | 1) + 48;
// load the superframe to do embedded signal processing
if(vc > 1 && vc < 6) //grab on vc1 values 2-5 B C D and E
if(vc > 1) //grab on vc1 values 2-5 B C D and E
{
state->dmr_embedded_signalling[internalslot][vc-1][i*2] = (1 & (dibit >> 1)); // bit 1
state->dmr_embedded_signalling[internalslot][vc-1][i*2+1] = (1 & dibit); // bit 0
@@ -180,17 +185,41 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
}
sync[24] = 0;
//test for RC sync pattern in MS sourced audio
if ( strcmp (sync, DMR_RC_DATA_SYNC) == 0)
{
state->dmr_ms_rc = 1;
fprintf (stderr, "%s ", getTime());
if (opts->inverted_dmr == 0)
{
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
}
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
fprintf (stderr, "| RC ");
fprintf (stderr, "\n");
}
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
EmbeddedSignallingOk = -1;
if(QR_16_7_6_decode(EmbeddedSignalling))
{
EmbeddedSignallingOk = 1;
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
power = EmbeddedSignalling[4];
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
}
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
for(i = 0; i < 18; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i+90] = dibit;
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
@@ -214,7 +243,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
for(i = 0; i < 36; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i+108] = dibit;
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
@@ -227,6 +256,20 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
}
//'DSP' output to file
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 10 ", state->currentslot+1); //0x10 for "voice burst", forced to slot 1
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
state->dmr_ms_mode = 1;
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
@@ -238,22 +281,28 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
memcpy (m2, ambe_fr2, sizeof(m2));
memcpy (m3, ambe_fr3, sizeof(m3));
if (state->directmode == 0)
if (state->dmr_ms_rc == 0)
{
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
else
{
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
if (state->directmode == 0)
{
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
else
{
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio on tdma direct
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
}
if (vc == 6)
{
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
//check the single burst/reverse channel opportunity
dmr_sbrc (opts, state, power);
fprintf (stderr, "\n");
dmr_alg_refresh (opts, state);
}
@@ -268,6 +317,12 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
state->last_vc_sync_time = time(NULL);
vc++;
//reset emb components
cc = 25;
power = 9; //power and pre-emption indicator
lcss = 9;
//this is necessary because we need to skip and collect dibits, not just skip them
if (vc > 6) goto END;
@@ -292,7 +347,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
dibit = getDibit(opts, state);
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
state->dmr_stereo_payload[i] = dibit;
@@ -379,7 +434,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
dibit = state->dmr_stereo_payload[i];
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
cachdata[i] = dibit;
}
@@ -398,7 +453,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
dibit = state->dmr_stereo_payload[i+12];
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
state->dmr_stereo_payload[i+12] = dibit;
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
@@ -425,7 +480,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
dibit = state->dmr_stereo_payload[i+48];
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
@@ -443,8 +498,9 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
state->dmr_stereo_payload[i+90] = dibit;
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
@@ -469,8 +525,9 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
dibit = (dibit ^ 2) & 3;
}
state->dmr_stereo_payload[i+108] = dibit;
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
@@ -481,6 +538,20 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
}
//'DSP' output to file
if (opts->use_dsp_output == 1)
{
FILE * pFile; //file pointer
pFile = fopen (opts->dsp_out_file, "a");
fprintf (pFile, "\n%d 10 ", state->currentslot+1); //0x10 for "voice burst", force to slot 1
for (i = 6; i < 72; i++) //33 bytes, no CACH
{
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
fprintf (pFile, "%X", dsp_byte);
}
fclose (pFile);
}
fprintf (stderr, "%s ", getTime());
if (opts->inverted_dmr == 0)
{
@@ -517,7 +588,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
}
//collect the mi fragment
dmr_late_entry_mi_fragment (opts, state, 1, ambe_fr, ambe_fr2, ambe_fr3);
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
//errors due to skipping other slot
// cach_err = dmr_cach (opts, state, cachdata);
@@ -558,7 +629,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
{
dibit = *dibit_p;
dibit_p++;
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i] = dibit;
}
@@ -566,7 +637,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
for (i = 0; i < 54; i++)
{
dibit = getDibit(opts, state);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
state->dmr_stereo_payload[i+90] = dibit;
}

View File

@@ -51,6 +51,7 @@ void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t block_len, uint8_t DMR
//maybe one day we will have more things to do here
state->data_conf_data[slot] = 0; //flag off confirmed data after processing it
state->data_p_head[slot] = 0; //flag off prop_head data after processing it
state->data_header_format[slot] = 0; //zero out so we don't keep ascii printing
}

View File

@@ -29,7 +29,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 1");
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
fprintf (stderr, "%s ", KNRM);
}
@@ -57,7 +57,7 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
{
fprintf (stderr, "%s ", KYEL);
fprintf (stderr, "\n Slot 2");
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
fprintf (stderr, " DMR PI H- ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
fprintf (stderr, "%s ", KNRM);
}
@@ -73,21 +73,6 @@ void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRC
}
}
if((IrrecoverableErrors == 0) && CRCCorrect)
{
//fprintf (stderr, " (PI CRC Okay)");
}
else if((IrrecoverableErrors == 0))
{
//fprintf (stderr, " (PI FEC Okay)");
}
else {
fprintf (stderr, "%s", KRED);
fprintf (stderr, (" (PI FEC ERR)"));
fprintf (stderr, "%s ", KNRM);
}
}
void LFSR(dsd_state * state)
@@ -114,7 +99,7 @@ void LFSR(dsd_state * state)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 1");
fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algid, state->payload_keyid);
fprintf(stderr, " Next MI: 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
}
@@ -127,7 +112,7 @@ void LFSR(dsd_state * state)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Slot 2");
fprintf (stderr, " DMR PI Continuation ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
fprintf (stderr, " DMR PI C- ALG ID: 0x%02X KEY ID: 0x%02X", state->payload_algidR, state->payload_keyidR);
fprintf(stderr, " Next MI: 0x%08X", lfsr);
fprintf (stderr, "%s", KNRM);
}

View File

@@ -4,7 +4,7 @@
//Original Source - https://github.com/LouisErigHerve/dsd
//Additional Functions
//Hamming17123, crc8, crc8ok functions
//Hamming17123, crc7, crc8, crc8ok functions
//Original Souce - https://github.com/boatbod/op25
#include "dsd.h"
@@ -121,6 +121,31 @@ bool crc8_ok(uint8_t bits[], unsigned int len)
return (crc == crc8(bits,len));
}
uint8_t crc7(uint8_t bits[], unsigned int len)
{
uint8_t crc=0;
unsigned int K = 7;
//G7(x) = x7 + x5 + x2 + x + 1 check poly below for correct (dmr rc crc7)
uint8_t poly[8] = {1,0,1,0,0,1,1,1}; // crc7 poly
uint8_t buf[256];
if (len+K > sizeof(buf)) {
// fprintf (stderr, "crc8: buffer length %u exceeds maximum %lu\n", len+K, sizeof(buf));
return 0;
}
memset (buf, 0, sizeof(buf));
for (unsigned int i=0; i<len; i++){
buf[i] = bits[i];
}
for (unsigned int i=0; i<len; i++)
if (buf[i])
for (unsigned int j=0; j<K+1; j++)
buf[i+j] ^= poly[j];
for (unsigned int i=0; i<K; i++){
crc = (crc << 1) + buf[len + i];
}
return crc;
}
/*
* @brief : This function compute the CRC-CCITT of the DMR data
* by using the polynomial x^16 + x^12 + x^5 + 1
@@ -329,4 +354,87 @@ uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @return The 9 bit CRC
*/
*/
uint16_t ComputeCrc9Bit(uint8_t * DMRData, uint32_t NbData)
{
uint32_t i;
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
/* Polynomial x^9 + x^6 + x^4 + x^3 + 1
* Normal = 0x059
* Reciprocal = 0x134
* Reversed reciprocal = 0x12C */
uint16_t Polynome = 0x059;
for(i = 0; i < NbData; i++)
{
if(((CRC >> 8) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
/* Conserve only the 9 LSBs */
CRC &= 0x01FF;
/* Invert the CRC */
CRC ^= 0x01FF;
/* Return the CRC */
return CRC;
} /* End ComputeCrc9Bit() */
/*
* @brief : This function compute the CRC-32 of the DMR data
* by using the polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
*
* @param Input : A buffer pointer of the DMR data (80 bytes)
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @param NbData : The number of bit to compute
* Rate 1/2 coded confirmed (10 data octets): 80 bit sequence (80 bytes)
* Rate 3/4 coded confirmed (16 data octets): 128 bit sequence (120 bytes)
* Rate 1 coded confirmed (22 data octets): 176 bit sequence (176 bytes)
*
* @return The 32 bit CRC
*/
uint32_t ComputeCrc32Bit(uint8_t * DMRData, uint32_t NbData)
{
uint32_t i;
uint32_t CRC = 0x00000000; /* Initialization value = 0x00000000 */
/* Polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
* Normal = 0x04C11DB7
* Reversed = 0xEDB88320
* Reciprocal = 0xDB710641
* Reversed reciprocal = 0x82608EDB */
uint32_t Polynome = 0x04C11DB7;
for(i = 0; i < NbData; i++)
{
if(((CRC >> 31) & 1) ^ (DMRData[i] & 1))
{
CRC = (CRC << 1) ^ Polynome;
}
else
{
CRC <<= 1;
}
}
//for whatever reason, we get the CRC returned in a reversed byte order (MSO LSO b***s***)
uint32_t a, b, c, d;
a = b = c = d = 0;
a = (CRC & 0xFF) << 24;
b = (CRC & 0xFF00) >> 8;
b = b << 16;
c = (CRC & 0xFF0000) >> 16;
c = c << 8;
d = (CRC & 0xFF000000) >> 24;
CRC = a + b + c + d;
/* Return the CRC */
return CRC;
} /* End ComputeCrc32Bit() */

View File

@@ -428,7 +428,7 @@ void processdPMRvoice (dsd_opts * opts, dsd_state * state)
if (state->R != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " KEY VALUE: [%05lld] ", state->R );
fprintf (stderr, " Key %05lld ", state->R );
fprintf (stderr, "%s", KNRM);
}
}

View File

@@ -34,7 +34,7 @@ char * getTimeF(void) //get pretty hh:mm:ss timestamp
}
char * getDateF(void) {
char datename[120]; //bug in 32-bit Ubuntu when using date in filename, date is garbage text
char datename[80]; //32-bit needs this to be 80
char * curr2;
struct tm * to;
time_t t;
@@ -45,8 +45,7 @@ char * getDateF(void) {
return curr2;
}
void
saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{
int i, j, k;
unsigned char b;
@@ -56,36 +55,22 @@ saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
fputc (err, opts->mbe_out_f);
k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this
{
//fprintf(stderr, "\n IMBE ");
}
for (i = 0; i < 11; i++)
{
b = 0;
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + imbe_d[k];
k++;
}
if (opts->payload == 1) //make opt variable later on to toggle this
{
//fprintf (stderr, "%02X", b);
}
fputc (b, opts->mbe_out_f);
}
if (opts->payload == 1)
{
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + imbe_d[k];
k++;
}
fputc (b, opts->mbe_out_f);
}
fflush (opts->mbe_out_f);
}
void
saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
@@ -95,42 +80,49 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
fputc (err, opts->mbe_out_f);
k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this
for (i = 0; i < 6; i++)
{
//fprintf(stderr, "\n AMBE ");
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
fputc (b, opts->mbe_out_f);
}
//for (i = 0; i < 6; i++)
for (i = 0; i < 6; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
{
//fprintf (stderr, "%02X", b);
}
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80?
{
//fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit?
}
fputc (b, opts->mbe_out_f);
}
if (opts->payload == 1)
{
//fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
b = ambe_d[48];
fputc (b, opts->mbe_out_f);
fflush (opts->mbe_out_f);
}
void
PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
void saveAmbe2450DataR (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
unsigned char err;
err = (unsigned char) state->errs2R;
fputc (err, opts->mbe_out_fR);
k = 0;
for (i = 0; i < 6; i++)
{
b = 0;
for (j = 0; j < 8; j++)
{
b = b << 1;
b = b + ambe_d[k];
k++;
}
fputc (b, opts->mbe_out_fR);
}
b = ambe_d[48];
fputc (b, opts->mbe_out_fR);
fflush (opts->mbe_out_fR);
}
void PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and ProVoice
{
int i, j, k;
unsigned char b;
@@ -165,8 +157,7 @@ PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and
//fprintf (stderr, "\n");
}
void
PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
void PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
@@ -333,14 +324,21 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
cookie[2] = fgetc (opts->mbe_in_f);
cookie[3] = fgetc (opts->mbe_in_f);
cookie[4] = 0;
//ambe+2
if (strstr (cookie, ".amb") != NULL)
{
state->mbe_file_type = 1;
}
{
state->mbe_file_type = 1;
}
//p1 and pv
else if (strstr (cookie, ".imb") != NULL)
{
state->mbe_file_type = 0;
}
{
state->mbe_file_type = 0;
}
//d-star ambe
else if (strstr (cookie, ".dmb") != NULL)
{
state->mbe_file_type = 2;
}
else
{
state->mbe_file_type = -1;
@@ -349,7 +347,7 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
}
//much simpler version
//slot 1
void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
{
if (opts->mbe_out == 1)
@@ -360,48 +358,67 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
fclose (opts->mbe_out_f);
opts->mbe_out_f = NULL;
opts->mbe_out = 0;
fprintf (stderr, "\nClosing MBE out file.");
fprintf (stderr, "\nClosing MBE out file 1.\n");
}
}
}
void
openMbeOutFile (dsd_opts * opts, dsd_state * state)
//slot 2
void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
{
if (opts->mbe_outR == 1)
{
if (opts->mbe_out_fR != NULL)
{
fflush (opts->mbe_out_fR);
fclose (opts->mbe_out_fR);
opts->mbe_out_fR = NULL;
opts->mbe_outR = 0;
fprintf (stderr, "\nClosing MBE out file 2.\n");
}
}
}
void openMbeOutFile (dsd_opts * opts, dsd_state * state)
{
int i, j;
char ext[5];
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
{
sprintf (ext, ".imb");
}
else
{
sprintf (ext, ".amb");
}
//phase 1 and provoice
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
{
sprintf (ext, ".imb");
}
//d-star
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
{
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
}
//dmr, nxdn, phase 2, x2-tdma
else sprintf (ext, ".amb");
// reset talkgroup id buffer
//reset talkgroup id buffer
for (i = 0; i < 12; i++)
{
for (j = 0; j < 25; j++)
{
for (j = 0; j < 25; j++)
{
state->tg[j][i] = 0;
}
state->tg[j][i] = 0;
}
}
state->tgcount = 0;
sprintf (opts->mbe_out_file, "%s %s%s", getDateF(), getTimeF(), ext);
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
opts->mbe_out_f = fopen (opts->mbe_out_path, "w");
if (opts->mbe_out_f == NULL)
{
fprintf (stderr,"Error, couldn't open %s\n", opts->mbe_out_path);
fprintf (stderr,"\nError, couldn't open %s for slot 1\n", opts->mbe_out_path);
}
else opts->mbe_out = 1;
@@ -411,8 +428,54 @@ openMbeOutFile (dsd_opts * opts, dsd_state * state)
fflush (opts->mbe_out_f);
}
void
openWavOutFile (dsd_opts * opts, dsd_state * state)
void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
{
int i, j;
char ext[5];
//phase 1 and provoice
if ( (state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15) )
{
sprintf (ext, ".imb");
}
//d-star
else if ( (state->synctype == 6) || (state->synctype == 7) || (state->synctype == 18) || (state->synctype == 19) )
{
sprintf (ext, ".dmb"); //new dstar file extension to make it read in and process properly
}
//dmr, nxdn, phase 2, x2-tdma
else sprintf (ext, ".amb");
//reset talkgroup id buffer
for (i = 0; i < 12; i++)
{
for (j = 0; j < 25; j++)
{
state->tg[j][i] = 0;
}
}
state->tgcount = 0;
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
opts->mbe_out_fR = fopen (opts->mbe_out_path, "w");
if (opts->mbe_out_fR == NULL)
{
fprintf (stderr,"\nError, couldn't open %s for slot 2\n", opts->mbe_out_path);
}
else opts->mbe_outR = 1;
//
fprintf (opts->mbe_out_fR, "%s", ext);
fflush (opts->mbe_out_fR);
}
void openWavOutFile (dsd_opts * opts, dsd_state * state)
{
SF_INFO info;

View File

@@ -87,8 +87,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
//NXDN FSW
if ((state->synctype == 28) || (state->synctype == 29))
{
nxdn_frame (opts, state);
//no MBEout...use symbol capture bin instead!
//MBEout restored, is not handled internally by nxdn_frame.c
nxdn_frame (opts, state);
return;
}
else if ((state->synctype == 6) || (state->synctype == 7))
@@ -107,7 +107,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
}
sprintf (state->fsubtype, " VOICE ");
processDSTAR (opts, state);
@@ -128,9 +128,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
{
openMbeOutFile (opts, state); //dstar ambe files are read back incorrectly, need to change file extension to differentiate when doing a playback
}
sprintf (state->fsubtype, " DATA ");
processDSTAR_HD (opts, state);
return;
@@ -141,9 +141,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
//print manufacturer strings to branding, disabled 0x10 moto other systems can use that fid set
//0x06 is trident, but when searching, apparently, they developed con+, but was bought by moto?
if (state->dmr_mfid == 0x10) ; //sprintf (state->dmr_branding, "%s", "Motorola");
else if (state->dmr_mfid == 0x68) sprintf (state->dmr_branding, "%s", "Hytera");
else if (state->dmr_mfid == 0x58) sprintf (state->dmr_branding, "%s", "Tait");
if (state->dmr_mfid == 0x10) ; //sprintf (state->dmr_branding, "%s", "Motorola");
else if (state->dmr_mfid == 0x68) sprintf (state->dmr_branding, "%s", " Hytera");
else if (state->dmr_mfid == 0x58) sprintf (state->dmr_branding, "%s", " Tait");
//disabling these due to random data decodes setting an odd mfid, could be legit, but only for that one packet?
//or, its just a decode error somewhere
@@ -164,70 +164,58 @@ processFrame (dsd_opts * opts, dsd_state * state)
//disable so radio id doesn't blink in and out during ncurses and aggressive_framesync
state->nac = 0;
//state->lastsrc = 0;
//state->lasttg = 0;
//state->lastsrcR = 0;
//state->lasttgR = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
}
if ( (state->synctype == 11) || (state->synctype == 12) || (state->synctype == 32) ) //DMR Voice Modes
{
sprintf (state->fsubtype, " VOICE ");
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL) && opts->dmr_stereo == 0)
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
if (opts->dmr_stereo == 0 && state->synctype < 32) // -T option for DMR (TDMA) stereo
{
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
dmrMSBootstrap (opts, state);
}
if (opts->dmr_mono == 1 && state->synctype == 32)
{
// fprintf (stderr, "%s", KRED);
// fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
// fprintf (stderr, "%s", KNRM);
dmrMSBootstrap (opts, state);
}
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
{
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
if (state->synctype > 31 )
{
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
}
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
}
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
//we can safely open MBE on any MS or mono handling
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
dmrMSBootstrap (opts, state);
}
if (opts->dmr_mono == 1 && state->synctype == 32)
{
//we can safely open MBE on any MS or mono handling
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
dmrMSBootstrap (opts, state);
}
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
{
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
if (state->synctype > 31 )
{
//we can safely open MBE on any MS or mono handling
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
dmrMSBootstrap (opts, state); //bootstrap into MS Bootstrap (voice only)
}
else dmrBSBootstrap (opts, state); //bootstrap into BS Bootstrap
}
}
else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
dmrMSData (opts, state);
// if (opts->dmr_stereo == 0)
// {
// closeMbeOutFile (opts, state);
// state->err_str[0] = 0;
// fprintf (stderr, "%s", KRED);
// fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
// fprintf (stderr, "%s", KNRM);
// }
// if (opts->dmr_stereo == 1)
// {
// dmrMSData (opts, state);
// }
}
else
{
if (opts->dmr_stereo == 0)
{
closeMbeOutFile (opts, state);
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
state->err_str[0] = 0;
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
@@ -237,6 +225,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
if (opts->dmr_stereo == 1)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
state->dmr_stereo = 0; //set the state to zero for handling pure data frames
sprintf (state->slot1light, " slot1 ");
sprintf (state->slot2light, " slot2 ");
@@ -246,7 +237,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
return;
}
else if ((state->synctype >= 2) && (state->synctype <= 5))
//X2-TDMA
else if ((state->synctype >= 2) && (state->synctype <= 5))
{
state->nac = 0;
if (opts->errorbars == 1)
@@ -256,15 +248,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
if ((state->synctype == 3) || (state->synctype == 4))
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processX2TDMAvoice (opts, state);
}
else
{
closeMbeOutFile (opts, state);
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
state->err_str[0] = 0;
processX2TDMAdata (opts, state);
}
@@ -272,21 +264,18 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
else if ((state->synctype == 14) || (state->synctype == 15))
{
//state->nac = 0;
//state->lastsrc = 0;
//state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
level = (int) state->max / 164;
//fprintf (stderr,"inlvl: %2i%% ", level);
}
}
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
{
openMbeOutFile (opts, state);
}
sprintf (state->fsubtype, " VOICE ");
processProVoice (opts, state);
return;
@@ -294,6 +283,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
//edacs
else if ((state->synctype == 37) || (state->synctype == 38))
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
edacs (opts, state);
return;
}
@@ -313,13 +303,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
//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 ");
//relocate MBEout to inside frame handling
processP2(opts, state);
return;
}
@@ -328,6 +312,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
/* dPMR Frame Sync 1 */
fprintf(stderr, "dPMR Frame Sync 1 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
else if ((state->synctype == 21) || (state->synctype == 25))
{
@@ -346,12 +331,12 @@ processFrame (dsd_opts * opts, dsd_state * state)
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf(state->fsubtype, " VOICE ");
processdPMRvoice (opts, state);
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf(state->fsubtype, " VOICE ");
processdPMRvoice (opts, state);
return;
@@ -360,11 +345,13 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
/* dPMR Frame Sync 3 */
fprintf(stderr, "dPMR Frame Sync 3 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
else if ((state->synctype == 23) || (state->synctype == 27))
{
/* dPMR Frame Sync 4 */
fprintf(stderr, "dPMR Frame Sync 4 ");
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
//dPMR
else //P25
@@ -463,15 +450,15 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
// Header Data Unit
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," HDU\n");
}
{
printFrameInfo (opts, state);
fprintf (stderr," HDU\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
openMbeOutFile (opts, state);
}
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_f == NULL) openMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lastp25type = 2;
state->dmrburstL = 25;
@@ -483,17 +470,17 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
// Logical Link Data Unit 1
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," LDU1 ");
}
{
printFrameInfo (opts, state);
fprintf (stderr," LDU1 ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
openMbeOutFile (opts, state);
}
}
state->lastp25type = 1;
state->dmrburstL = 26;
state->currentslot = 0;
@@ -514,27 +501,27 @@ processFrame (dsd_opts * opts, dsd_state * state)
if (state->lastp25type != 1)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n");
}
{
printFrameInfo (opts, state);
fprintf (stderr,"\n Ignoring LDU2 not preceeded by LDU1\n");
}
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
}
else
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," LDU2 ");
}
{
printFrameInfo (opts, state);
fprintf (stderr," LDU2 ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
openMbeOutFile (opts, state);
}
}
state->lastp25type = 2;
sprintf (state->fsubtype, " LDU2 ");
state->numtdulc = 0;
@@ -546,14 +533,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
// Terminator with subsequent Link Control
state->dmrburstL = 28;
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," TDULC\n");
}
{
printFrameInfo (opts, state);
fprintf (stderr," TDULC\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
}
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0;
state->lastsrc = 0;
@@ -562,9 +549,9 @@ processFrame (dsd_opts * opts, dsd_state * state)
sprintf (state->fsubtype, " TDULC ");
state->numtdulc++;
if ((opts->resume > 0) && (state->numtdulc > opts->resume))
{
resumeScan (opts, state);
}
{
resumeScan (opts, state);
}
processTDULC (opts, state);
state->err_str[0] = 0;
}
@@ -573,14 +560,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
// Terminator without subsequent Link Control
state->dmrburstL = 28;
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," TDU\n");
}
{
printFrameInfo (opts, state);
fprintf (stderr," TDU\n");
}
if (opts->mbe_out_dir[0] != 0)
{
closeMbeOutFile (opts, state);
}
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
state->lasttg = 0;
state->lastsrc = 0;
@@ -594,120 +581,126 @@ processFrame (dsd_opts * opts, dsd_state * state)
{
state->dmrburstL = 29;
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," TSBK");
}
{
printFrameInfo (opts, state);
fprintf (stderr," TSBK");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
if (opts->resume > 0)
{
resumeScan (opts, state);
}
{
resumeScan (opts, state);
}
state->lasttg = 0;
state->lastsrc = 0;
state->lastp25type = 3;
sprintf (state->fsubtype, " TSBK ");
// Now processing NID
processTSBK(opts, state);
}
else if (strcmp (duid, "30") == 0)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," PDU\n");
}
if (opts->resume > 0)
{
resumeScan (opts, state);
}
{
printFrameInfo (opts, state);
fprintf (stderr," PDU\n"); //multi block/packet PDU
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
{
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
if (opts->resume > 0)
{
resumeScan (opts, state);
}
state->lastp25type = 4;
sprintf (state->fsubtype, " PDU ");
}
// try to guess based on previous frame if unknown type
else if (state->lastp25type == 1)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr,"(LDU2) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU2
state->lastp25type = 2;
sprintf (state->fsubtype, "(LDU2) ");
state->numtdulc = 0;
processLDU2 (opts, state);
}
else if (state->lastp25type == 2)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr,"(LDU1) ");
}
if (opts->mbe_out_dir[0] != 0)
{
if (opts->mbe_out_f == NULL)
{
openMbeOutFile (opts, state);
}
}
//state->lastp25type = 0;
// Guess that the state is LDU1
state->lastp25type = 1;
sprintf (state->fsubtype, "(LDU1) ");
state->numtdulc = 0;
processLDU1 (opts, state);
}
else if (state->lastp25type == 3)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," (TSBK)\n");
}
//state->lastp25type = 0;
// Guess that the state is TSBK
state->lastp25type = 3;
sprintf (state->fsubtype, "(TSBK) ");
// Now processing NID
skipDibit (opts, state, 328-25);
}
else if (state->lastp25type == 4)
{
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," (PDU)\n");
}
state->lastp25type = 0;
}
// try to guess based on previous frame if unknown type
// disabling the guessing game on P1
// else if (state->lastp25type == 1)
// {
// if (opts->errorbars == 1)
// {
// printFrameInfo (opts, state);
// fprintf (stderr,"(LDU2) ");
// }
// // if (opts->mbe_out_dir[0] != 0)
// // {
// // if (opts->mbe_out_f == NULL)
// // {
// // openMbeOutFile (opts, state);
// // }
// // }
// //state->lastp25type = 0;
// // Guess that the state is LDU2
// state->lastp25type = 2;
// sprintf (state->fsubtype, "(LDU2) ");
// state->numtdulc = 0;
// processLDU2 (opts, state);
// }
// else if (state->lastp25type == 2)
// {
// if (opts->errorbars == 1)
// {
// printFrameInfo (opts, state);
// fprintf (stderr,"(LDU1) ");
// }
// if (opts->mbe_out_dir[0] != 0)
// {
// if (opts->mbe_out_f == NULL)
// {
// openMbeOutFile (opts, state);
// }
// }
// //state->lastp25type = 0;
// // Guess that the state is LDU1
// state->lastp25type = 1;
// sprintf (state->fsubtype, "(LDU1) ");
// state->numtdulc = 0;
// processLDU1 (opts, state);
// }
// else if (state->lastp25type == 3)
// {
// if (opts->errorbars == 1)
// {
// printFrameInfo (opts, state);
// fprintf (stderr," (TSBK)\n");
// }
// //state->lastp25type = 0;
// // Guess that the state is TSBK
// state->lastp25type = 3;
// sprintf (state->fsubtype, "(TSBK) ");
// // Now processing NID
// skipDibit (opts, state, 328-25);
// }
// else if (state->lastp25type == 4)
// {
// if (opts->errorbars == 1)
// {
// printFrameInfo (opts, state);
// fprintf (stderr," (PDU)\n");
// }
// state->lastp25type = 0;
// }
else
{
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
if (opts->errorbars == 1)
{
state->lastp25type = 0;
sprintf (state->fsubtype, " ");
if (opts->errorbars == 1)
{
printFrameInfo (opts, state);
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
// fprintf (stderr, "\n"); //prints on dPMR frame 3
}
printFrameInfo (opts, state);
fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
// fprintf (stderr, "\n"); //prints on dPMR frame 3
}
}
}

View File

@@ -145,3 +145,48 @@ int csvChanImport(dsd_opts * opts, dsd_state * state) //channel map import
fclose(fp);
return 0;
}
int csvKeyImport(dsd_opts * opts, dsd_state * state) //multi-key support for NXDN
{
char filename[1024] = "filename.csv";
sprintf (filename, "%s", opts->key_in_file);
char buffer[BSIZE];
FILE * fp;
fp = fopen(filename, "r");
if (fp == NULL) {
printf("Unable to open file '%s'\n", filename);
exit(1);
}
int row_count = 0;
int field_count = 0;
unsigned long long int keynumber;
while (fgets(buffer, BSIZE, fp)) {
field_count = 0;
row_count++;
if (row_count == 1)
continue; //don't want labels
char * field = strtok(buffer, ","); //seperate by comma
while (field) {
if (field_count == 0)
{
sscanf (field, "%lld", &keynumber);
}
if (field_count == 1)
{
sscanf (field, "%lld", &state->rkey_array[keynumber]);
}
field = strtok(NULL, ",");
field_count++;
}
fprintf (stderr, "Key [%03lld] [%05lld]", keynumber, state->rkey_array[keynumber]);
fprintf (stderr, "\n");
}
fclose(fp);
return 0;
}

View File

@@ -52,7 +52,7 @@ char * FM_banner[9] = {
" ██║ ██║ ╚═══██╗██║ ██║   ██╔══╝ ██║╚██╔╝██║██╔══╝ ",
" ██████╔╝██████╔╝██████╔╝   ██║ ██║ ╚═╝ ██║███████╗",
" ╚═════╝ ╚═════╝ ╚═════╝    ╚═╝ ╚═╝ ╚═╝╚══════╝",
" 'Lite' Edition v2.0.0-8-g235eeed Windows 32-bit RC2 "
" 'Lite' Edition v2.0.0-28-ga02f992 Windows 32-bit RC3 "
};
int
@@ -69,6 +69,7 @@ comp (const void *a, const void *b)
//struct for checking existence of directory to write to
struct stat st = {0};
char wav_file_directory[1024] = {0};
char dsp_filename[1024] = {0};
unsigned long long int p2vars = 0;
char * pEnd; //bugfix
@@ -135,10 +136,11 @@ noCarrier (dsd_opts * opts, dsd_state * state)
state->dmr_payload_p = state->dibit_buf + 200;
memset (state->dmr_payload_buf, 0, sizeof (int) * 200);
//dmr buffer end
if (opts->mbe_out_f != NULL)
{
closeMbeOutFile (opts, state);
}
//close MBE out files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
state->jitter = -1;
state->lastsynctype = -1;
state->carrier = 0;
@@ -301,6 +303,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
//initialize unified dmr pdu 'superframe'
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
//init confirmed data individual block crc as invalid
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
@@ -319,8 +322,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
//REMUS! multi-purpose call_string
sprintf (state->call_string[0], "%s", " "); //20 spaces
sprintf (state->call_string[1], "%s", " "); //20 spaces
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
if (time(NULL) - state->last_cc_sync_time > 30) //thirty seconds of no carrier
{
@@ -375,8 +378,10 @@ initOpts (dsd_opts * opts)
opts->playoffsetR = 0;
opts->mbe_out_dir[0] = 0;
opts->mbe_out_file[0] = 0;
opts->mbe_out_fileR[0] = 0; //second slot on a TDMA system
opts->mbe_out_path[0] = 0;
opts->mbe_out_f = NULL;
opts->mbe_out_fR = NULL; //second slot on a TDMA system
opts->audio_gain = 0; //0
opts->audio_gainR = 0; //0
opts->audio_out = 1;
@@ -389,11 +394,13 @@ initOpts (dsd_opts * opts)
opts->group_in_file[0] = 0;
opts->lcn_in_file[0] = 0;
opts->chan_in_file[0] = 0;
opts->key_in_file[0] = 0;
//end import filenames
opts->szNumbers[0] = 0;
opts->symbol_out_f = NULL;
opts->symbol_out = 0;
opts->mbe_out = 0;
opts->mbe_outR = 0; //second slot on a TDMA system
opts->wav_out_f = NULL;
opts->wav_out_fR = NULL;
opts->wav_out_raw = NULL;
@@ -523,6 +530,10 @@ initOpts (dsd_opts * opts)
//this is a fix to cygwin stuttering when both slots have voice
opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
//dsp structured file
opts->dsp_out_file[0] = 0;
opts->use_dsp_output = 0;
} //initopts
void
@@ -694,10 +705,12 @@ initState (dsd_state * state)
state->dmr_stereo = 0; //1, or 0?
state->dmrburstL = 17; //initialize at higher value than possible
state->dmrburstR = 17; //17 in char array is set for ERR
state->dmr_so = 0;
state->dmr_soR = 0;
state->dmr_fid = 0;
state->dmr_fidR = 0;
state->dmr_so = 0;
state->dmr_soR = 0;
state->dmr_fid = 0;
state->dmr_fidR = 0;
state->dmr_flco = 0;
state->dmr_flcoR = 0;
state->dmr_ms_mode = 0;
state->HYTL = 0;
@@ -741,6 +754,8 @@ initState (dsd_state * state)
state->p2_wacn = 0;
state->p2_sysid = 0;
state->p2_cc = 0;
state->p2_siteid = 0;
state->p2_rfssid = 0;
state->p2_hardset = 0;
state->p2_is_lcch = 0;
state->p25_cc_is_tdma = 2; //init on 2, TSBK NET_STS will set 0, TDMA NET_STS will set 1. //used to determine if we need to change symbol rate when cc hunting
@@ -790,9 +805,6 @@ initState (dsd_state * state)
//dmr trunking/ncurses stuff
state->dmr_rest_channel = -1; //init on -1
state->dmr_mfid = -1; //
state->dmr_tuned_lcn = -1; //logical slot, lcn * ts?
state->dmr_vc_lcn = -1; //
state->dmr_vc_lsn = -1;
//new nxdn stuff
state->nxdn_part_of_frame = 0;
@@ -806,7 +818,10 @@ initState (dsd_state * state)
//site/srv/cch info
state->nxdn_location_site_code = 0;
state->nxdn_location_sys_code = 0;
sprintf (state->nxdn_location_category, "%s", " ");
sprintf (state->nxdn_location_category, "%s", " ");
//multi-key array
memset (state->rkey_array, 0, sizeof(state->rkey_array));
//Remus DMR End Call Alert Beep
state->dmr_end_alert[0] = 0;
@@ -818,6 +833,7 @@ initState (dsd_state * state)
//initialize unified dmr pdu 'superframe'
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
memset (state->cap_plus_csbk_bits, 0, sizeof(state->cap_plus_csbk_bits));
//init confirmed data individual block crc as invalid
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
@@ -837,8 +853,8 @@ initState (dsd_state * state)
memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
//REMUS! multi-purpose call_string
sprintf (state->call_string[0], "%s", " "); //20 spaces
sprintf (state->call_string[1], "%s", " "); //20 spaces
sprintf (state->call_string[0], "%s", " "); //21 spaces
sprintf (state->call_string[1], "%s", " "); //21 spaces
//late entry mi fragments
memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment));
@@ -885,7 +901,7 @@ usage ()
printf (" -o <device> Audio output device (default is /dev/dsp)\n");
printf (" null for no audio output\n");
printf (" pulse for pulse audio \n");
printf (" -d <dir> Create mbe data files, use this directory\n");
printf (" -d <dir> Create mbe data files, use this directory (TDMA version is experimental)\n");
printf (" -r <files> Read/Play saved mbe data from file(s)\n");
printf (" -g <num> Audio output gain (default = 0 = auto, disable = -1)\n");
printf (" -w <file> Output synthesized speech to a .wav file, legacy auto modes only.\n");
@@ -895,6 +911,7 @@ usage ()
printf (" -a Enable Call Alert Beep (NCurses Terminal Only)\n");
printf (" (Warning! Might be annoying.)\n");
printf (" -L <file> Specify Filename for LRRP Data Output.\n");
printf (" -Q <file> Specify Filename for DSP Structured File Output. (placed in DSP folder)\n");
printf (" -c <file> Output symbol capture to .bin file\n");
printf (" -q Reverse Mute - Mute Unencrypted Voice and Unmute Encrypted Voice\n");
printf (" -V Enable Audio Smoothing on Upsampled 48k/1 or 24k/2 Audio (Capital V)\n");
@@ -914,9 +931,9 @@ usage ()
printf (" Example: dsd-fme-lite -fp -i rtl:0:851.375M:22:-2:12:0:6021\n");
printf ("\n");
printf ("Decoder options:\n");
printf (" -fa Legacy Auto Detection 8k/1 (old methods default)\n");
printf (" -fa Legacy Auto Detection (old methods default)\n");
printf (" -ft XDMA P25 and DMR BS/MS frame types (new default)\n");
printf (" -fs DMR Stereo BS and MS Simplex only\n");
printf (" -fs DMR Stereo BS and MS Simplex\n");
printf (" -f1 Decode only P25 Phase 1\n");
printf (" -fd Decode only D-STAR\n");
printf (" -fr Decode only DMR Mono - Single Slot Voice\n");
@@ -925,7 +942,7 @@ usage ()
printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
printf (" -fp Decode only EDACS/ProVoice*\n");
printf (" -fm Decode only dPMR*\n");
printf (" -l Disable DMR and NXDN input filtering\n");
printf (" -l Disable DMR, dPMR, and NXDN input filtering\n");
printf (" -u <num> Unvoiced speech quality (default=3)\n");
printf (" -xx Expect non-inverted X2-TDMA signal\n");
printf (" -xr Expect inverted DMR signal\n");
@@ -953,9 +970,8 @@ usage ()
//printf (" (4 Level, not 8 Level LSM) (this is honestly unknown since I can't verify what local systems are using)\n");
printf (" -F Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
printf (" Use this feature to allow MAC_SIGNAL even if CRC errors.\n");
printf (" -F Relax DMR CACH/Burst FEC Pass/Fail - Passive Frame Sync\n");
printf (" Use if skipping occurs, but may cause wonky audio due to loss of good sync\n");
printf (" -F Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n");
printf (" Enabling on some systems could lead to bad voice/data decoding if bad or marginal signal\n");
printf ("\n");
printf (" -K <dec> Manually Enter Basic Privacy Key (Decimal Value of Key Number)\n");
printf ("\n");
@@ -966,6 +982,7 @@ usage ()
printf (" -H '20029736A5D91042 C923EB0697484433 005EFC58A1905195 E28E9C7836AA2DB8' \n");
printf ("\n");
printf (" -R <dec> Manually Enter dPMR or NXDN EHR Scrambler Key Value (Decimal Value)\n");
printf (" -k <file> Import NXDN Scrambler Key List from csv file.\n");
printf (" \n");
printf (" -4 Force Privacy Key over FID and SVC bits \n");
printf ("\n");
@@ -1047,6 +1064,7 @@ if (opts->audio_in_type == 0)
if (opts->audio_out_type == 0)
{
// openPulseInput(opts); //test to see if we still randomly hang up in ncurses and tcp input if we open this and leave it opened
openPulseOutput(opts);
}
@@ -1116,10 +1134,10 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state)
{
closeSymbolOutFile (opts, state);
}
if (opts->mbe_out_f != NULL)
{
closeMbeOutFile (opts, state);
}
//close MBE out files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
fprintf (stderr,"\n");
fprintf (stderr,"Total audio errors: %i\n", state->debug_audio_errors);
@@ -1201,7 +1219,7 @@ main (int argc, char **argv)
exitflag = 0;
// signal (SIGINT, sigfun);
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQWrlZTF01:2:345:6:7:89:E")) != -1)
while ((c = getopt (argc, argv, "haepPqs:t:v:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:VU:Y:K:H:X:NQ:WrlZTF01:2:345:6:7:89:Ek:")) != -1)
{
opterr = 0;
switch (c)
@@ -1219,6 +1237,29 @@ main (int argc, char **argv)
//Disabled the Serial Port Dev and Baud Rate, etc, If somebody uses that function, sorry...
case 'k': //NXDN multi-key loader
strncpy(opts.key_in_file, optarg, 1023);
opts.key_in_file[1023] = '\0';
csvKeyImport(&opts, &state);
break;
case 'Q': //'DSP' Structured Output file for OKDMRlib
sprintf (wav_file_directory, "./DSP");
wav_file_directory[1023] = '\0';
if (stat(wav_file_directory, &st) == -1)
{
fprintf (stderr, "-Q %s DSP file directory does not exist\n", wav_file_directory);
fprintf (stderr, "Creating directory %s to save DSP Structured files\n", wav_file_directory);
mkdir(wav_file_directory, 0700); //user read write execute, needs execute for some reason or segfault
}
//read in filename
//sprintf (opts.wav_out_file, "./WAV/DSD-FME-X1.wav");
strncpy(dsp_filename, optarg, 1023);
sprintf(opts.dsp_out_file, "%s/%s", wav_file_directory, dsp_filename);
fprintf (stderr, "Saving DSP Structured files to %s\n", opts.dsp_out_file);
opts.use_dsp_output = 1;
break;
case 'z':
sscanf (optarg, "%d", &opts.slot_preference);
opts.slot_preference--; //user inputs 1 or 2, internally we want 0 and 1
@@ -1479,7 +1520,7 @@ main (int argc, char **argv)
wav_file_directory[1023] = '\0';
if (stat(wav_file_directory, &st) == -1)
{
fprintf (stderr, "-T %s WAV file directory does not exist\n", wav_file_directory);
fprintf (stderr, "-P %s WAV file directory does not exist\n", wav_file_directory);
fprintf (stderr, "Creating directory %s to save decoded wav files\n", wav_file_directory);
mkdir(wav_file_directory, 0700); //user read write execute, needs execute for some reason or segfault
}
@@ -1496,7 +1537,7 @@ main (int argc, char **argv)
fprintf (stderr, "%s", KYEL);
//fprintf (stderr,"DMR Stereo Aggressive Resync Disabled!\n");
fprintf (stderr, "Relax P25 Phase 2 MAC_SIGNAL CRC Checksum Pass/Fail\n");
fprintf (stderr, "Relax DMR CACH/Burst FEC Pass/Fail\n");
fprintf (stderr, "Relax DMR CACH/Burst FEC or RAS/CRC CSBK Pass/Fail\n");
fprintf (stderr, "%s", KNRM);
break;
@@ -1598,10 +1639,10 @@ main (int argc, char **argv)
opts.frame_dpmr = 0;
opts.frame_provoice = 0;
opts.frame_ysf = 0;
opts.pulse_digi_rate_out = 8000; //doesn't matter for /dev/dsp anyways
opts.pulse_digi_rate_out = 48000; // /dev/dsp does need this set to 48000 to properly process the upsampling
opts.pulse_digi_out_channels = 1;
opts.dmr_stereo = 0;
opts.dmr_mono = 1;
opts.dmr_stereo = 1; //switching in 'stereo' for 'mono'
opts.dmr_mono = 0;
state.dmr_stereo = 0;
opts.setmod_bw = 7000;
sprintf (opts.output_name, "Legacy Auto");
@@ -1884,7 +1925,7 @@ main (int argc, char **argv)
opts.setmod_bw = 7000;
sprintf (opts.output_name, "DMR Mono");
//fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n");
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo or XDMA is highly encouraged.\n");
fprintf (stderr,"Decoding only DMR Mono. \nUsing DMR Stereo '-fs' or XDMA '-ft' is highly encouraged.\n");
//dmr stereo below
// opts.frame_dstar = 0;
// opts.frame_x2tdma = 0;
@@ -2338,13 +2379,13 @@ main (int argc, char **argv)
opts.playoffsetR = 0;
opts.delay = 0;
if (strlen(opts.wav_out_file) > 0 && opts.dmr_stereo_wav == 0)
{
openWavOutFile (&opts, &state);
}
else
{
openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
}
{
openWavOutFile (&opts, &state);
}
opts.pulse_digi_rate_out = 48000;
opts.pulse_digi_out_channels = 1;
if (opts.audio_out_type == 0) openPulseOutput(&opts); //need to open it up for output?
if (opts.audio_out_type == 5) openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
}
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
@@ -2379,10 +2420,7 @@ main (int argc, char **argv)
if (opts.playfiles == 1)
{
opts.pulse_digi_rate_out = 48000;
opts.pulse_digi_out_channels = 1;
// openPulseOutput(&opts); //need to open it up for output?
openAudioInDevice (&opts); //needs to be tested, not sure if required
state.aout_gain = 25; //BUGFIX: No audio output when playing back .amb/.imb files
playMbeFiles (&opts, &state, argc, argv);
}

View File

@@ -17,8 +17,42 @@
#include "dsd.h"
void
playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
int Pr[256] = {
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255
};
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
{
int i;
@@ -26,99 +60,79 @@ playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
char ambe_d[49];
for (i = state->optind; i < argc; i++)
{
sprintf (opts->mbe_in_file, "%s", argv[i]);
openMbeInFile (opts, state);
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
fprintf (stderr, "playing %s\n", opts->mbe_in_file);
while (feof (opts->mbe_in_f) == 0)
{
sprintf (opts->mbe_in_file, "%s", argv[i]);
openMbeInFile (opts, state);
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
fprintf (stderr, "playing %s\n", opts->mbe_in_file);
while (feof (opts->mbe_in_f) == 0)
if (state->mbe_file_type == 0)
{
readImbe4400Data (opts, state, imbe_d);
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->audio_out == 1)
{
if (state->mbe_file_type == 0)
{
readImbe4400Data (opts, state, imbe_d);
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->audio_out == 1)
{
processAudio(opts, state);
}
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
else if (state->mbe_file_type == 1)
{
readAmbe2450Data (opts, state, 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->audio_out == 1)
{
processAudio(opts, state);
}
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
if (exitflag == 1)
{
cleanupAndExit (opts, state);
}
processAudio(opts, state);
}
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
else if (state->mbe_file_type > 0) //ambe files
{
readAmbe2450Data (opts, state, ambe_d);
int j, x;
unsigned long long int k;
if (state->K != 0) //apply Pr key
{
k = Pr[state->K];
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
for (short int j = 0; j < 48; j++) //49
{
x = ( ((k << j) & 0x800000000000) >> 47 );
ambe_d[j] ^= x;
}
}
//ambe+2
if (state->mbe_file_type == 1) 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);
//dstar ambe
if (state->mbe_file_type == 2) mbe_processAmbe2400Dataf (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->audio_out == 1)
{
processAudio(opts, state);
}
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
playSynthesizedVoice (opts, state);
}
}
if (exitflag == 1)
{
cleanupAndExit (opts, state);
}
}
}
}
void
processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
{
//
int Pr[256] = {
0x0000, 0x1F00, 0xE300, 0xFC00, 0x2503, 0x3A03, 0xC603, 0xD903,
0x4A05, 0x5505, 0xA905, 0xB605, 0x6F06, 0x7006, 0x8C06, 0x9306,
0x2618, 0x3918, 0xC518, 0xDA18, 0x031B, 0x1C1B, 0xE01B, 0xFF1B,
0x6C1D, 0x731D, 0x8F1D, 0x901D, 0x491E, 0x561E, 0xAA1E, 0xB51E, //31
0x4B28, 0x5428, 0xA828, 0xB728, 0x6E2B, 0x712B, 0x8D2B, 0x922B,
0x012D, 0x1E2D, 0xE22D, 0xFD2D, 0x242E, 0x3B2E, 0xC72E, 0xD82E,
0x6D30, 0x7230, 0x8E30, 0x9130, 0x4833, 0x5733, 0xAB33, 0xB433,
0x2735, 0x3835, 0xC435, 0xDB35, 0x0236, 0x1D36, 0xE136, 0xFE36, //63
0x2B49, 0x3449, 0xC849, 0xD749, 0x0E4A, 0x114A, 0xED4A, 0xF24A,
0x614C, 0xAE4C, 0x824C, 0x9D4C, 0x444F, 0x5B4F, 0xA74F, 0xB84F,
0x0D51, 0x1251, 0xEE51, 0xF151, 0x2852, 0x3752, 0xCB52, 0xD452,
0x4754, 0x5854, 0xA454, 0xBB54, 0x6257, 0x7D57, 0x8157, 0x9E57, //95
0x6061, 0x7F61, 0x8361, 0x9C61, 0x4562, 0x5A62, 0xA662, 0xB962,
0x2A64, 0x3564, 0xC964, 0xD664, 0x0F67, 0x1067, 0xEC67, 0xF367,
0x4679, 0x5979, 0xA579, 0xBA79, 0x637A, 0x7C7A, 0x807A, 0x9F7A,
0x0C7C, 0x137C, 0xEF7C, 0xF07C, 0x297F, 0x367F, 0xCA7F, 0xD57F, //127
0x4D89, 0x5289, 0xAE89, 0xB189, 0x688A, 0x778A, 0x8B8A, 0x948A,
0x078C, 0x188C, 0xE48C, 0xFB8C, 0x228F, 0x3D8F, 0xC18F, 0xDE8F,
0x6B91, 0x7491, 0x8891, 0x9791, 0x4E92, 0x5192, 0xAD92, 0xB292,
0x2194, 0x3E94, 0xC294, 0xDD94, 0x0497, 0x1B97, 0xE797, 0xF897, //159
0x06A1, 0x19A1, 0xE5A1, 0xFAA1, 0x23A2, 0x3CA2, 0xC0A2, 0xDFA2,
0x4CA4, 0x53A4, 0xAFA4, 0xB0A4, 0x69A7, 0x76A7, 0x8AA7, 0x95A7,
0x20B9, 0x3FB9, 0xC3B9, 0xDCB9, 0x05BA, 0x1ABA, 0xE6BA, 0xF9BA,
0x6ABC, 0x75BC, 0x89BC, 0x96BC, 0x4FBF, 0x50BF, 0xACBF, 0xB3BF, //191
0x66C0, 0x79C0, 0x85C0, 0x9AC0, 0x43C3, 0x5CC3, 0xA0C3, 0xBFC3,
0x2CC5, 0x33C5, 0xCFC5, 0xD0C5, 0x09C6, 0x16C6, 0xEAC6, 0xF5C6,
0x84D0, 0x85DF, 0x8AD3, 0x8BDC, 0xB6D5, 0xB7DA, 0xB8D6, 0xB9D9,
0xD0DA, 0xD1D5, 0xDED9, 0xDFD6, 0xE2DF, 0xE3D0, 0xECDC, 0xEDD3, //223
0x2DE8, 0x32E8, 0xCEE8, 0xD1E8, 0x08EB, 0x17EB, 0xEBEB, 0xF4EB,
0x67ED, 0x78ED, 0x84ED, 0x9BED, 0x42EE, 0x5DEE, 0xA1EE, 0xBEEE,
0x0BF0, 0x14F0, 0xE8F0, 0xF7F0, 0x2EF3, 0x31F3, 0xCDF3, 0xD2F3,
0x41F5, 0x5EF5, 0xA2F5, 0xBDF5, 0x64F6, 0x7BF6, 0x87F6, 0x98F6 //255
};
//
int i;
char imbe_d[88];
char ambe_d[49];
@@ -364,6 +378,13 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
{
PrintAMBEData (opts, state, ambe_d);
}
//restore MBE file save, slot 1 -- consider saving even if enc
if (opts->mbe_out_f != NULL && (state->dmr_encL == 0 || opts->dmr_mute_encL == 0) )
{
saveAmbe2450Data (opts, state, ambe_d);
}
}
//stereo slots and slot 1 (right slot)
if (state->currentslot == 1) //&& opts->dmr_stereo == 1
@@ -458,6 +479,12 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
{
PrintAMBEData (opts, state, ambe_d);
}
//restore MBE file save, slot 2 -- consider saving even if enc
if (opts->mbe_out_fR != NULL && (state->dmr_encR == 0 || opts->dmr_mute_encR == 0) )
{
saveAmbe2450DataR (opts, state, ambe_d);
}
}
//X2-TDMA? Not sure what still makes it this far to run under Framef

View File

@@ -840,8 +840,13 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
if(opts->tcp_file_in == NULL)
{
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
sprintf (opts->audio_in_dev, "%s", "pulse");
opts->audio_in_type = 0;
if (opts->audio_out_type == 0)
{
sprintf (opts->audio_in_dev, "%s", "pulse");
opts->audio_in_type = 0;
}
else opts->audio_in_type = 5;
}
state->audio_smoothing = 0; //disable smoothing to prevent random crackling/buzzing
@@ -971,7 +976,8 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
}
}
opts->audio_in_type = 0; //set after closing to prevent above crash condition
if (opts->audio_out_type == 0) opts->audio_in_type = 0; //set after closing to prevent above crash condition
else (opts->audio_in_type = 5);
choicec = 18; //exit
}
@@ -1684,35 +1690,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->audio_in_type != 1) //can't run getch/menu when using STDIN -
{
timeout(0);
c = getch();
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
//use rtl_udp_tune
#ifdef USE_RTLSDR
if (temp_freq == opts->rtlsdr_center_freq)
{
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
memset((char * ) & address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(SRV_IP); //address of host
address.sin_port = htons(udp_port);
sendto(handle, data, UDP_BUFLEN, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
rtl_udp_tune (opts, state, temp_freq);
temp_freq = -1;
}
#endif
//Variable reset/set section
//carrier reset
// if (state->carrier == 0) //reset these to 0 when no carrier
// {
// sprintf(state->dmr_branding, "%s", "");
// }
//set lls sync types
if (state->synctype >= 0 && state->synctype < 39)
{
@@ -1908,7 +1900,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
}
if (opts->call_alert == 1)
if (opts->call_alert == 1 && rd != 0 && tg != 0)
{
//fprintf (stderr, "BEEP 0 MS LEFT\n");
beeper (opts, state, 0);
@@ -1951,7 +1943,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
}
if (opts->call_alert == 1)
if (opts->call_alert == 1 && rd != 0 && tg != 0)
{
//fprintf (stderr, "BEEP 0 BS LEFT\n");
beeper (opts, state, 0);
@@ -1993,7 +1985,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
openWavOutFileR (opts, state); //testing for now, will want to move to per call later
}
if (opts->call_alert == 1)
if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
{
//fprintf (stderr, "BEEP 1 BS RIGHT\n");
beeper (opts, state, 1);
@@ -2048,11 +2040,19 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
// {
// beeper (opts, state, 0);
// state->dmr_end_alert[0] = 1; //don't play again until new voice frames
// state->lasttg = 0;
// state->lastsrc = 0;
// rd = 0;
// tg = 0;
// }
// if (state->dmrburstR == 2 && state->dmr_end_alert[1] == 0) //if TLC and flag not tripped
// {
// beeper (opts, state, 1);
// state->dmr_end_alert[1] = 1; //don't play again until new voice frames
// state->lasttgR = 0;
// state->lastsrcR = 0;
// rdR = 0;
// tgR = 0;
// }
// }
@@ -2061,7 +2061,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (opts->ncurses_compact == 1)
{
printw ("------------------------------------------------------------------------------\n");
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-8-g235eeed RC2");
printw ("| Digital Speech Decoder: Florida Man Edition - Win32 %s \n", "v2.0.0-28-ga02f992 RC3");
}
if (opts->ncurses_compact == 0)
{
@@ -2072,8 +2072,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
if (i == 1) printw (" ESC to Menu");
if (i == 2) printw (" 'q' to Quit ");
if (i == 4) printw (" MBElib %s", versionstr);
if (i == 5) printw (" %s ", "Win32 RC2"); //printw (" %s \n", GIT_TAG);
if (i == 6) printw (" %s \n", "v2.0.0-8-g235eeed"); //printw (" %s \n", GIT_TAG);
if (i == 5) printw (" %s ", "Win32 RC3"); //printw (" %s \n", GIT_TAG);
if (i == 6) printw (" %s \n", "v2.0.0-28-ga02f992"); //printw (" %s \n", GIT_TAG);
else printw ("\n");
}
attroff(COLOR_PAIR(6)); //6
@@ -2372,7 +2372,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
else if (lls == 0 || lls == 1) //P1
{
printw ("P25 P1 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
// printw ("P25 P1 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
printw ("P25 P1 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
if (state->p25_cc_freq != 0)
{
printw ("Freq: [%.06lf] MHz", (double)state->p25_cc_freq/1000000);
@@ -2380,7 +2381,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
else if (lls == 35 || lls == 36) //P2
{
printw ("P25 P2 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
// printw ("P25 P2 - WACN: [%05llX] SYS: [%03llX] NAC: [%03llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc);
printw ("P25 P2 - [%05llX][%03llX][%03llX] RFSS: [%llX] SITE: [%llX] ", state->p2_wacn, state->p2_sysid, state->p2_cc, state->p2_rfssid, state->p2_siteid);
if (state->p2_wacn == 0 || state->p2_sysid == 0 || state->p2_cc == 0)
{
attron(COLOR_PAIR(2));
@@ -2920,8 +2922,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
printw ("--Call History----------------------------------------------------------------\n");
for (short int j = 0; j < 10; j++)
{
//only print if a valid time was assigned to the matrix, and not EDACS/PV
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 )
//only print if a valid time was assigned to the matrix, and not EDACS/PV, and source is not zero
if ( ((time(NULL) - call_matrix[9-j][5]) < 999999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 && call_matrix[9-j][2] != 0) //
{
printw ("| %s ", SyncTypes[call_matrix[9-j][0]]);
if (lls == 28 || lls == 29)
@@ -3122,21 +3124,24 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
}
if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
{
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);
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: ; //do nothing
}
//
// if (c == 32) //'space bar' replay last bin file (rework to do wav files too?)
// {
// 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);
// 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: ; //do nothing
// }
//
if (c == 80) //'P' key - start per call wav files
{
@@ -3169,28 +3174,34 @@ if (c == 112) //'p' key - stop all per call wav files
opts->dmr_stereo_wav = 0;
}
//
// if (c == 115) //'s' key, stop playing wav or symbol in files
// {
// if (opts->symbolfile != NULL)
// {
// if (opts->audio_in_type == 4)
// {
// fclose(opts->symbolfile);
// }
// }
if (c == 115) //'s' key, stop playing wav or symbol in files
{
if (opts->symbolfile != NULL)
{
if (opts->audio_in_type == 4)
{
fclose(opts->symbolfile);
}
}
// if (opts->audio_in_type == 2) //wav input file
// {
// sf_close(opts->audio_in_file);
// }
if (opts->audio_in_type == 2) //wav input file
{
sf_close(opts->audio_in_file);
}
// if (opts->audio_out_type == 0)
// {
// opts->audio_in_type = 0;
// openPulseInput(opts);
// }
// else opts->audio_in_type = 5;//cleanupAndExit(opts, state);
// }
//
opts->audio_in_type = 0;
openPulseInput(opts);
}
//Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
//WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
// //Lockout bug in EDACS prevents any group from tuning when using this, not sure why yet
// //WARNING! USE THESE WITH CAUTION! IF BREAKING ISSUES OBSERVED, THEN RESTART AND DON'T USE THEM!!
if (opts->frame_provoice != 1 && c == 49) //'1' key, lockout slot 1 or conventional tg from tuning/playback during session
{
state->group_array[state->group_tally].groupNumber = state->lasttg;
@@ -3253,6 +3264,38 @@ if (opts->p25_trunk == 1 && c == 103) //'g' key, toggle tune group calls
else opts->trunk_tune_group_calls = 1;
}
if (c == 70) //'F' key - toggle agressive sync/crc failure/ras
{
if (opts->aggressive_framesync == 0) opts->aggressive_framesync = 1;
else opts->aggressive_framesync = 0;
}
if (c == 68) //'D' key - Reset DMR Site Parms/Call Strings, etc.
{
//dmr trunking/ncurses stuff
state->dmr_rest_channel = -1; //init on -1
state->dmr_mfid = -1; //
//dmr mfid branding and site parms
sprintf(state->dmr_branding_sub, "%s", "");
sprintf(state->dmr_branding, "%s", "");
sprintf (state->dmr_site_parms, "%s", "");
//DMR Location Area - DMRLA B***S***
opts->dmr_dmrla_is_set = 0;
opts->dmr_dmrla_n = 0;
}
//Debug/Troubleshooting Option
if (c == 90) //'Z' key - Simulate NoCarrier/No VC/CC sync to zero out more stuff (capital Z)
{
// opts->p25_is_tuned = 0;
state->last_cc_sync_time = 0;
state->last_vc_sync_time = 0;
noCarrier(opts, state);
}
//anything with an entry box will need the inputs and outputs stopped first
//so probably just write a function to handle c input, and when c = certain values
//needing an entry box, then stop all of those

View File

@@ -273,4 +273,9 @@ void rtl_udp_tune(dsd_opts * opts, dsd_state * state, long int frequency)
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //make user configurable later
address.sin_port = htons(udp_port);
sendto(handle, data, 5, 0, (const struct sockaddr * ) & address, sizeof(struct sockaddr_in));
//BUGFIX: This was causing an indefinite number of UDP sockets to stay open on each tune request
//we open a new socket with each request, so we need to close the socket after writing to it
//this would cause the tuning to stop after x number of tune attempts (few hours? on a busy system)
close (handle); //close socket after sending.
}

View File

@@ -312,11 +312,11 @@ void map_isch()
isch_map["fb063f092"] = 127;
}
unsigned long long int isch_lookup (unsigned long long int isch)
int isch_lookup (unsigned long long int isch)
{
map_isch(); //initialize the lookup map
char s[64];
unsigned long long int decoded = -2; //initialize lookup to an invalid number
int decoded = -2; //initialize lookup to an invalid number
sprintf(s, "%llx", isch);
decoded = isch_map[s];
return(decoded);

View File

@@ -287,6 +287,13 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
//rigctl
if (opts->use_rigctl == 1)
{
//extra safeguards due to sync issues with NXDN
memset (state->nxdn_sacch_frame_segment, 0, sizeof(state->nxdn_sacch_frame_segment));
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
state->lastsynctype = -1;
state->last_cc_sync_time = time(NULL);
//
if (opts->setmod_bw != 0 ) SetModulation(opts->rigctl_sockfd, opts->setmod_bw);
SetFreq(opts->rigctl_sockfd, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
@@ -295,6 +302,13 @@ void NXDN_decode_VCALL_ASSGN(dsd_opts * opts, dsd_state * state, uint8_t * Messa
//rtl_udp
else if (opts->audio_in_type == 3)
{
//extra safeguards due to sync issues with NXDN
memset (state->nxdn_sacch_frame_segment, 0, sizeof(state->nxdn_sacch_frame_segment));
memset (state->nxdn_sacch_frame_segcrc, 1, sizeof(state->nxdn_sacch_frame_segcrc));
state->lastsynctype = -1;
state->last_cc_sync_time = time(NULL);
//
rtl_udp_tune (opts, state, freq);
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
opts->p25_is_tuned = 1;
@@ -653,6 +667,9 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
fprintf (stderr, "%s", KNRM);
}
//check the rkey array for a scrambler key value
if (state->rkey_array[KeyID] != 0) state->R = state->rkey_array[KeyID];
if (state->nxdn_cipher_type == 0x01 && state->R > 0) //scrambler key value
{
fprintf (stderr, "%s", KYEL);

View File

@@ -247,7 +247,30 @@ void nxdn_frame (dsd_opts * opts, dsd_state * state)
if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits);
if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a);
if (facch & 2) nxdn_deperm_facch(opts, state, facch_bits_b);
if (voice) nxdn_voice (opts, state, voice, dbuf);
if (voice)
{
//restore MBE file open here
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
//update last voice sync time
state->last_vc_sync_time = time(NULL);
//process voice frame
nxdn_voice (opts, state, voice, dbuf);
}
//close MBE file if no voice and its open
if (!voice)
{
if (opts->mbe_out_f != NULL)
{
if (opts->frame_nxdn96 == 1) //nxdn96 has voice and data mixed together, so we will need to do a time check first
{
if ( (time(NULL) - state->last_vc_sync_time) > 1) //test for optimal time, 1 sec should be okay
{
closeMbeOutFile (opts, state);
}
}
if (opts->frame_nxdn48 == 1) closeMbeOutFile (opts, state); //okay to close right away if nxdn48, no data/voice mixing
}
}
fprintf (stderr, "\n");
END: ; //do nothing

View File

@@ -76,7 +76,7 @@ int vc_counter = 0;
int framing_counter = 0;
unsigned long long int isch = 0;
unsigned long long int isch_decoded = 0;
int isch_decoded = -1;
int p2_duid[8] = {0};
int16_t duid_decoded = 0;
@@ -369,7 +369,7 @@ void process_ISCH (dsd_opts * opts, dsd_state * state)
{
isch_decoded = isch_lookup(isch);
if (isch_decoded > 0)
if (isch_decoded > -1)
{
int uf_count = isch_decoded & 0x3;
int free = (isch_decoded >> 2) & 0x1;
@@ -411,6 +411,7 @@ void process_ISCH (dsd_opts * opts, dsd_state * state)
}
isch_decoded = -1; //reset to bad value after running
}
@@ -693,10 +694,20 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
if (state->currentslot == 0 && duid_decoded != 3 && duid_decoded != 12)
{
fprintf (stderr, "VCH 0 ");
//open MBEout file - slot 1 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
}
}
else if (state->currentslot == 1 && duid_decoded != 3 && duid_decoded != 12)
{
fprintf (stderr, "VCH 1 ");
//open MBEout file - slot 2 - USE WITH CAUTION on Phase 2! Consider using a symbol capture bin instead!
if (duid_decoded == 0 || duid_decoded == 6) //4V or 2V (voice)
{
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
}
}
else fprintf (stderr, "VCH S ");
@@ -835,6 +846,16 @@ void processP2 (dsd_opts * opts, dsd_state * state)
//process DUID will run through all collected frames and handle them appropriately
process_P2_DUID (opts, state);
state->dmr_stereo = 0;
state->p2_is_lcch = 0;
state->p2_is_lcch = 0;
//bugfix for OSS dmrbust 16 shim, reset both to 0 upon exit
//in case or marginal signal and both get stuck on 16, indefinitely muting the non-preferred slot
//but...this can also cause at least one 4v/2v to get through on the other slot if the sync lines up that way
if (opts->audio_out_type == 5)
{
//set both to blank value
state->dmrburstL = 17;
state->dmrburstR = 17;
}
fprintf (stderr, "\n");
}

View File

@@ -915,6 +915,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, "\n RFSS Status Broadcast - Implicit \n");
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X] CHAN [%04X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channel, sysclass);
process_channel_to_freq (opts, state, channel);
state->p2_siteid = siteid;
state->p2_rfssid = rfssid;
}
//RFSS Status Broadcast - Explicit
@@ -931,6 +934,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
fprintf (stderr, " LRA [%02X] SYSID [%03X] RFSS ID [%02X] SITE ID [%02X]\n CHAN-T [%04X] CHAN-R [%02X] SSC [%02X] ", lra, lsysid, rfssid, siteid, channelt, channelr, sysclass);
process_channel_to_freq (opts, state, channelt);
process_channel_to_freq (opts, state, channelr);
state->p2_siteid = siteid;
state->p2_rfssid = rfssid;
}
//Unit-to-Unit Answer Request (UU_ANS_REQ)
@@ -1079,6 +1085,9 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
process_channel_to_freq (opts, state, channelr);
}
state->p2_siteid = siteid;
state->p2_rfssid = rfssid;
}
//Secondary Control Channel Broadcast, Implicit
@@ -1108,7 +1117,10 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
state->trunk_lcn_freq[1] = freq1;
state->trunk_lcn_freq[2] = freq2;
state->lcn_freq_count = 3; //increment to three
}
}
state->p2_siteid = siteid;
state->p2_rfssid = rfssid;
}

View File

@@ -202,6 +202,10 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//print it and then zero out
state->lastsrc = 0;
state->lasttg = 0;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
if (state->currentslot == 0)
{
@@ -218,6 +222,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
//print it and then zero out
state->lastsrcR = 0;
state->lasttgR = 0;
//close any open MBEout files
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
fprintf (stderr, "%s", KNRM);
}
@@ -232,8 +239,9 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
}
if (opcode == 0x4 && err == 0)
{
if (state->currentslot == 1) state->dmrburstL = 21;
else state->dmrburstR = 21;
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
//if (state->currentslot == 1) state->dmrburstL = 21;
//else state->dmrburstR = 21;
fprintf (stderr, " MAC_ACTIVE ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 1, SMAC);
@@ -241,8 +249,18 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
}
if (opcode == 0x6 && err == 0)
{
if (state->currentslot == 1) state->dmrburstL = 22;
else state->dmrburstR = 22;
if (state->currentslot == 1)
{
state->dmrburstL = 21;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
else
{
state->dmrburstR = 21;
//close any open MBEout files
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
fprintf (stderr, " MAC_HANGTIME ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 1, SMAC);
@@ -412,6 +430,10 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//print it and then zero out
state->lastsrc = 0;
state->lasttg = 0;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
if (state->currentslot == 1)
{
@@ -428,6 +450,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
//print it and then zero out
state->lastsrcR = 0;
state->lasttgR = 0;
//close any open MBEout files
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
fprintf (stderr, "%s", KNRM);
}
@@ -462,8 +487,9 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
}
if (opcode == 0x4 && err == 0)
{
if (state->currentslot == 0) state->dmrburstL = 21;
else state->dmrburstR = 21;
//disable to prevent blinking in ncurses terminal due to OSS preemption shim
//if (state->currentslot == 0) state->dmrburstL = 21;
//else state->dmrburstR = 21;
fprintf (stderr, " MAC_ACTIVE ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 0, FMAC);
@@ -471,8 +497,18 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
}
if (opcode == 0x6 && err == 0)
{
if (state->currentslot == 0) state->dmrburstL = 22;
else state->dmrburstR = 22;
if (state->currentslot == 0)
{
state->dmrburstL = 22;
//close any open MBEout files
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
}
else
{
state->dmrburstR = 22;
//close any open MBEout files
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
}
fprintf (stderr, " MAC_HANGTIME ");
fprintf (stderr, "%s", KYEL);
process_MAC_VPDU(opts, state, 0, FMAC);

View File

@@ -33,11 +33,11 @@ processProVoice (dsd_opts * opts, dsd_state * state)
#ifdef PROVOICE_DUMP
fprintf (stderr," ");
#endif
//init Bits (64)...MI?
//iNitial 64 bits
if (opts->payload == 1)
{
k = 0;
//fprintf (stderr, "\nInit 64 ");
fprintf (stderr, "\n N64: ");
for(i = 0; i < 8; i++)
{
initbyte[i] = 0;
@@ -47,9 +47,10 @@ processProVoice (dsd_opts * opts, dsd_state * state)
initbyte[i] = initbyte[i] | init[k];
k++;
}
//fprintf (stderr, "%02X", initbyte[i]);
fprintf (stderr, "%02X", initbyte[i]);
if (i == 3) fprintf (stderr, "-");
}
//fprintf (stderr, "\n");
fprintf (stderr, "\n");
}
// lid
for (i = 0; i < 16; i++)
@@ -79,7 +80,7 @@ processProVoice (dsd_opts * opts, dsd_state * state)
if (opts->payload == 1)
{
k = 0;
//fprintf (stderr, "LID ");
fprintf (stderr, " LID: ");
for(i = 0; i < 10; i++)
{
lidbyte[i] = 0;
@@ -89,9 +90,10 @@ processProVoice (dsd_opts * opts, dsd_state * state)
lidbyte[i] = lidbyte[i] | lid[k];
k++;
}
//fprintf (stderr, "%02X", lidbyte[i]);
fprintf (stderr, "%02X", lidbyte[i]);
if (i == 3 || i == 7) fprintf (stderr, "-");
}
//fprintf (stderr, "\n");
// fprintf (stderr, "\n");
}
@@ -337,7 +339,7 @@ processProVoice (dsd_opts * opts, dsd_state * state)
if (opts->payload == 1)
{
k = 0;
//fprintf (stderr, "16 bits? ");
fprintf (stderr, "\n 16B: ");
for(i = 0; i < 2; i++)
{
initbyte[i] = 0;
@@ -347,9 +349,9 @@ if (opts->payload == 1)
initbyte[i] = initbyte[i] | init[k];
k++;
}
//fprintf (stderr, "%02X", initbyte[i]);
fprintf (stderr, "%02X", initbyte[i]);
}
//fprintf (stderr, "\n");
// fprintf (stderr, "\n");
}
// imbe frames 3,4 first half
w = pW;