mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef07b48540 | ||
|
|
db67a8b227 | ||
|
|
4e2c4577d5 | ||
|
|
e581c96560 | ||
|
|
f3505269d0 | ||
|
|
20ccdbbced | ||
|
|
fc2fb99502 | ||
|
|
143c560958 | ||
|
|
d122d7e935 | ||
|
|
d0f9bb4bad | ||
|
|
ac752029bd | ||
|
|
5b994f5129 | ||
|
|
ec7d7c24a5 | ||
|
|
1d49481f2d | ||
|
|
7ca8cb421c | ||
|
|
4eb44b3c67 | ||
|
|
e16e4b61fc | ||
|
|
fbd04fa869 | ||
|
|
7f9b852f36 | ||
|
|
f5a7ab2b77 | ||
|
|
ffe6098fb8 | ||
|
|
157ca8c043 |
@@ -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.
|
||||
|
||||
|
||||
8
examples/nxdn_chan_map.csv
Normal file
8
examples/nxdn_chan_map.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
channel(dec), freq(Hz)
|
||||
141,423862500
|
||||
142,424337500
|
||||
143,424912500
|
||||
203,424100000
|
||||
204,424625000
|
||||
271,422650000
|
||||
302,423287500
|
||||
|
5
examples/nxdn_sc_key.csv
Normal file
5
examples/nxdn_sc_key.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key(dec), value(dec), load any single keys as key 0
|
||||
0,23466
|
||||
1,12345
|
||||
2,32700
|
||||
63,32767
|
||||
|
@@ -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);
|
||||
|
||||
62
src/bptc.c
62
src/bptc.c
@@ -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() */
|
||||
|
||||
|
||||
134
src/dmr_block.c
134
src/dmr_block.c
@@ -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));
|
||||
}
|
||||
94
src/dmr_bs.c
94
src/dmr_bs.c
@@ -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");
|
||||
|
||||
486
src/dmr_csbk.c
486
src/dmr_csbk.c
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
280
src/dmr_dburst.c
280
src/dmr_dburst.c
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
178
src/dmr_flco.c
178
src/dmr_flco.c
@@ -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);
|
||||
|
||||
154
src/dmr_le.c
154
src/dmr_le.c
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
121
src/dmr_ms.c
121
src/dmr_ms.c
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
23
src/dmr_pi.c
23
src/dmr_pi.c
@@ -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);
|
||||
}
|
||||
|
||||
112
src/dmr_utils.c
112
src/dmr_utils.c
@@ -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() */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
237
src/dsd_file.c
237
src/dsd_file.c
@@ -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;
|
||||
|
||||
451
src/dsd_frame.c
451
src/dsd_frame.c
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
130
src/dsd_main.c
130
src/dsd_main.c
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
197
src/dsd_mbe.c
197
src/dsd_mbe.c
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user