mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
DMR Reorganization; Initial Trunking Support;
This commit is contained in:
161
include/dsd.h
161
include/dsd.h
@@ -138,48 +138,6 @@ typedef struct
|
||||
uint8_t bytes[3];
|
||||
} rs_12_9_checksum_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char VoiceFrame[3][72]; /* 3 x 72 bit of voice per time slot frame */
|
||||
char Sync[48]; /* 48 bit of data or SYNC per time slot frame */
|
||||
}TimeSlotRawVoiceFrame_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char DeInterleavedVoiceSample[3][4][24]; /* 3 x (4 x 24) deinterleaved bit of voice per time slot frame */
|
||||
}TimeSlotDeinterleavedVoiceFrame_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int errs1[3]; /* 3 x errors #1 computed when demodulate the AMBE voice bit of the frame */
|
||||
int errs2[3]; /* 3 x errors #2 computed when demodulate the AMBE voice bit of the frame */
|
||||
char AmbeBit[3][49]; /* 3 x 49 bit of AMBE voice of the frame */
|
||||
}TimeSlotAmbeVoiceFrame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int ProtectFlag;
|
||||
unsigned int Reserved;
|
||||
unsigned int FullLinkControlOpcode;
|
||||
unsigned int FeatureSetID;
|
||||
unsigned int ServiceOptions;
|
||||
unsigned int GroupAddress; /* Destination ID or TG (in Air Interface format) */
|
||||
unsigned int SourceAddress; /* Source ID (in Air Interface format) */
|
||||
unsigned int DataValidity; /* 0 = All Full LC data are incorrect ; 1 = Full LC data are correct (CRC checked OK) */
|
||||
unsigned int LeftOvers; //what is the 8 bits for that isn't used
|
||||
}FullLinkControlPDU_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TimeSlotRawVoiceFrame_t TimeSlotRawVoiceFrame[6]; /* A voice superframe contains 6 timeslot voice frame */
|
||||
TimeSlotDeinterleavedVoiceFrame_t TimeSlotDeinterleavedVoiceFrame[6];
|
||||
TimeSlotAmbeVoiceFrame_t TimeSlotAmbeVoiceFrame[6];
|
||||
FullLinkControlPDU_t FullLC;
|
||||
} TimeSlotVoiceSuperFrame_t;
|
||||
|
||||
|
||||
//dPMR
|
||||
/* Could only be 2 or 4 */
|
||||
#define NB_OF_DPMR_VOICE_FRAME_TO_DECODE 2
|
||||
@@ -321,6 +279,7 @@ typedef struct
|
||||
int inverted_dpmr;
|
||||
int frame_dpmr;
|
||||
|
||||
short int dmr_mono;
|
||||
short int dmr_stereo;
|
||||
short int lrrp_file_output;
|
||||
|
||||
@@ -528,12 +487,8 @@ typedef struct
|
||||
char slot1light[8];
|
||||
char slot2light[8];
|
||||
int directmode;
|
||||
TimeSlotVoiceSuperFrame_t TS1SuperFrame;
|
||||
TimeSlotVoiceSuperFrame_t TS2SuperFrame;
|
||||
|
||||
char dmr_branding[25];
|
||||
uint8_t dmr_12_rate_sf[2][288]; //was 84, expanded to 288 to prevent possible crash if more comes in than expected
|
||||
uint8_t dmr_34_rate_sf[2][288]; //was 96, expanded to 288 to prevent possible crash if more comes in than expected
|
||||
int dmr_stereo_payload[144]; //load up 144 dibit buffer for every single DMR TDMA frame
|
||||
uint8_t data_header_blocks[2]; //collect number of blocks to follow from data header per slot
|
||||
uint8_t data_header_padding[2]; //collect number of padding octets in last block per slot
|
||||
@@ -542,27 +497,23 @@ typedef struct
|
||||
uint8_t data_block_counter[2]; //counter for number of data blocks collected
|
||||
uint8_t data_p_head[2]; //flag for dmr proprietary header to follow
|
||||
|
||||
//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 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_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.
|
||||
|
||||
//dmr talker alias new/fixed stuff
|
||||
uint8_t dmr_alias_format[2]; //per slot
|
||||
uint8_t dmr_alias_len[2]; //per slot
|
||||
char dmr_alias_block_segment[2][4][7][16]; //2 slots, by 4 blocks, by up to 7 alias bytes that are up to 16-bit chars
|
||||
|
||||
|
||||
dPMRVoiceFS2Frame_t dPMRVoiceFS2Frame;
|
||||
|
||||
//These flags are used to known the DMR frame
|
||||
//printing format (hex or binary)
|
||||
int printDMRRawVoiceFrameHex;
|
||||
int printDMRRawVoiceFrameBin;
|
||||
int printDMRRawDataFrameHex;
|
||||
int printDMRRawDataFrameBin;
|
||||
int printDMRAmbeVoiceSampleHex;
|
||||
int printDMRAmbeVoiceSampleBin;
|
||||
|
||||
//These flags are used to known the dPMR frame
|
||||
//orinting format (hex or binary)
|
||||
int printdPMRRawVoiceFrameHex;
|
||||
int printdPMRRawVoiceFrameBin;
|
||||
int printdPMRRawDataFrameHex;
|
||||
int printdPMRRawDataFrameBin;
|
||||
int printdPMRAmbeVoiceSampleHex;
|
||||
int printdPMRAmbeVoiceSampleBin;
|
||||
|
||||
unsigned char * dpmr_caller_id;
|
||||
unsigned char * dpmr_target_id;
|
||||
int dpmr_color_code;
|
||||
@@ -572,6 +523,8 @@ typedef struct
|
||||
short int dmr_ms_mode;
|
||||
unsigned int dmrburstL;
|
||||
unsigned int dmrburstR;
|
||||
int dropL;
|
||||
int dropR;
|
||||
unsigned long long int R;
|
||||
unsigned long long int RR;
|
||||
unsigned long long int H;
|
||||
@@ -654,6 +607,11 @@ typedef struct
|
||||
uint32_t nxdn_location_sys_code;
|
||||
uint16_t nxdn_location_site_code;
|
||||
|
||||
//dmr late entry mi
|
||||
uint64_t late_entry_mi_fragment[2][7][3];
|
||||
|
||||
//char dmr_branding[25]; //may need higher value?
|
||||
char dmr_branding_sub[25];
|
||||
|
||||
//Roman DMR End Call Alert Beep
|
||||
int dmr_end_alert[2]; //dmr TLC end call alert beep has already played once flag
|
||||
@@ -733,13 +691,7 @@ typedef struct
|
||||
/*
|
||||
* function prototypes
|
||||
*/
|
||||
void processDMRdata (dsd_opts * opts, dsd_state * state);
|
||||
void processDMRvoice (dsd_opts * opts, dsd_state * state);
|
||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||
void dmrBS (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMS (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMSData (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
void processdPMRvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processAudio (dsd_opts * opts, dsd_state * state);
|
||||
void processAudioR (dsd_opts * opts, dsd_state * state);
|
||||
@@ -799,8 +751,7 @@ void resumeScan (dsd_opts * opts, dsd_state * state);
|
||||
int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
|
||||
void upsample (dsd_state * state, float invalue);
|
||||
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNVoice (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNData (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
||||
void processHDU (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU1 (dsd_opts * opts, dsd_state * state);
|
||||
@@ -836,14 +787,14 @@ void nxdn_deperm_facch2_udch (dsd_opts * opts, dsd_state * state, uint8_t bits[3
|
||||
void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType);
|
||||
void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]);
|
||||
|
||||
//OP25 NXDN CRC functions
|
||||
//OP25 NXDN CRC functions
|
||||
static inline int load_i(const uint8_t val[], int len);
|
||||
static uint8_t crc6(const uint8_t buf[], int len);
|
||||
static uint16_t crc12f(const uint8_t buf[], int len);
|
||||
static uint16_t crc15(const uint8_t buf[], int len);
|
||||
static uint16_t crc16cac(const uint8_t buf[], int len);
|
||||
|
||||
/* NXDN functions */
|
||||
/* NXDN Convolution functions */
|
||||
void CNXDNConvolution_start(void);
|
||||
void CNXDNConvolution_decode(uint8_t s0, uint8_t s1);
|
||||
void CNXDNConvolution_chainback(unsigned char* out, unsigned int nBits);
|
||||
@@ -867,8 +818,6 @@ void NXDN_decode_site_info(dsd_opts * opts, dsd_state * state, uint8_t * Message
|
||||
void nxdn_location_id_handler (dsd_state * state, uint32_t location_id);
|
||||
|
||||
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||
void printdPMRAmbeVoiceSample(dsd_opts * opts, dsd_state * state);
|
||||
void printdPMRRawVoiceFrame (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
//dPMR functions
|
||||
void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferOut, uint32_t NbOfBitToScramble);
|
||||
@@ -878,9 +827,6 @@ uint8_t CRC8BitdPMR(uint8_t * BufferIn, uint32_t BitLength);
|
||||
void ConvertAirInterfaceID(uint32_t AI_ID, uint8_t ID[8]);
|
||||
int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24]);
|
||||
|
||||
void ProcessDMR (dsd_opts * opts, dsd_state * state);
|
||||
void DMRDataFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||
void DMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
|
||||
//BPTC (Block Product Turbo Code) functions
|
||||
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]);
|
||||
@@ -893,26 +839,49 @@ uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome);
|
||||
rs_12_9_correct_errors_result_t rs_12_9_correct_errors(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome, uint8_t *errors_found);
|
||||
rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword);
|
||||
|
||||
//SYNC DMR data extraction functions
|
||||
void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state);
|
||||
//DMR CRC Functions
|
||||
uint16_t ComputeCrcCCITT(uint8_t * DMRData);
|
||||
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask);
|
||||
uint8_t ComputeCrc5Bit(uint8_t * DMRData);
|
||||
uint8_t * DmrAlgIdToStr(uint8_t AlgID);
|
||||
uint8_t * DmrAlgPrivacyModeToStr(uint32_t PrivacyMode);
|
||||
|
||||
void ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessCSBK(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessDataData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void Process1Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void Process12Data(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void Process34Data(dsd_opts * opts, dsd_state * state, unsigned char tdibits[98], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessMBCData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessMBChData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessReservedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
void ProcessUnifiedData(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
//new simplified dmr functions
|
||||
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst);
|
||||
void dmr_data_sync (dsd_opts * opts, dsd_state * state);
|
||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type);
|
||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[]);
|
||||
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25]);
|
||||
|
||||
//Embedded Alias and GPS
|
||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[]);
|
||||
|
||||
//"DMR STEREO"
|
||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||
void dmrBS (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMS (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMSData (dsd_opts * opts, dsd_state * state);
|
||||
void dmrMSBootstrap (dsd_opts * opts, dsd_state * state);
|
||||
|
||||
//dmr data header and multi block types (header, 1/2, 3/4, 1, Unified)
|
||||
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors);
|
||||
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type);
|
||||
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]);
|
||||
void dmr_lrrp (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]);
|
||||
uint8_t dmr_lrrp_check (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[]);
|
||||
|
||||
//dmr alg stuff
|
||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state);
|
||||
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);
|
||||
|
||||
//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);
|
||||
|
||||
//LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
void LFSR(dsd_state * state);
|
||||
|
||||
392
src/dmr_block.c
Normal file
392
src/dmr_block.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_block.c
|
||||
* DMR Data Header and Data Block Assembly/Handling
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//clear out unified pdu 'superframe' slot
|
||||
for (short int i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i] = 0;
|
||||
}
|
||||
|
||||
//TODO: ONLY RUN ON GOOD CRC?
|
||||
|
||||
//collect relevant data header info, figure out format, and grab appropriate info from it
|
||||
if (state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "%s ", KGRN);
|
||||
state->data_block_counter[slot] = 1; //reset block counter to 1
|
||||
state->data_header_format[slot] = dheader[0]; //collect the entire byte, we can check group or individual, response requested as well on this
|
||||
state->data_header_sap[slot] = (dheader[1] & 0xF0) >> 4;
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0x2)
|
||||
{
|
||||
state->data_conf_data[slot] = 0; //flag as unconfirmed data, no need for additional CRC/Serial checks
|
||||
state->data_header_padding[slot] = dheader[1] & 0xF; //number of padding octets on last block
|
||||
state->data_header_blocks[slot] = dheader[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data
|
||||
fprintf (stderr, "\n Unconfirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X",
|
||||
state->data_header_format[slot] & 0xF, state->data_header_sap[slot],
|
||||
state->data_header_blocks[slot], state->data_header_padding[slot] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0x3)
|
||||
{
|
||||
state->data_conf_data[slot] = 1; //set flag to indicate the following blocks are confirmed data so we know to run additional CRC etc on it.
|
||||
state->data_header_padding[slot] = dheader[1] & 0xF; //number of padding octets on last block
|
||||
state->data_header_blocks[slot] = dheader[8] & 0x7F; //number of blocks to follow, most useful for when to poll the super array for data
|
||||
fprintf (stderr, "\n Confirmed Data Header: DPF %01X - SAP %02X - Block Count %02X - Padding Octets %02X",
|
||||
state->data_header_format[slot] & 0xF, state->data_header_sap[slot],
|
||||
state->data_header_blocks[slot], state->data_header_padding[slot] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xD) //DD_HEAD
|
||||
{
|
||||
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",
|
||||
state->data_header_format[slot] & 0xF, state->data_header_sap[slot],
|
||||
state->data_header_blocks[slot], state->data_header_padding[slot] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xE) //SP_HEAD or R_HEAD
|
||||
{
|
||||
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",
|
||||
state->data_header_format[slot] & 0xF, state->data_header_sap[slot],
|
||||
state->data_header_blocks[slot], state->data_header_padding[slot] );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//do we still need this? since we have ample PDU storage
|
||||
if (state->data_header_blocks[slot] > 7)
|
||||
{
|
||||
state->data_header_blocks[slot] = 7;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
//end collecting data header info
|
||||
|
||||
fprintf (stderr, "%s ", KMAG);
|
||||
|
||||
if (state->data_header_sap[slot] == 0x4 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n IP Data - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
|
||||
sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ",
|
||||
( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]),
|
||||
( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) );
|
||||
|
||||
|
||||
state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7];
|
||||
|
||||
}
|
||||
|
||||
if (state->data_header_sap[slot] == 0x0 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Unified Data Transport - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
|
||||
sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ",
|
||||
( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]),
|
||||
( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) );
|
||||
|
||||
state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7];
|
||||
|
||||
}
|
||||
|
||||
if (state->data_header_sap[slot] == 0x9 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Proprietary Packet Data - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
|
||||
sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ",
|
||||
( (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7]),
|
||||
( (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4]) );
|
||||
|
||||
state->dmr_lrrp_source[slot] = (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7];
|
||||
|
||||
}
|
||||
|
||||
if (state->data_header_sap[slot] == 0x2 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n TCP/IP Header Compression Data - Source: ");
|
||||
fprintf (stderr, "[%d]", dheader[3]);
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", dheader[2]);
|
||||
|
||||
sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ",
|
||||
dheader[3], dheader[2] );
|
||||
|
||||
state->dmr_lrrp_source[slot] = dheader[3];
|
||||
|
||||
}
|
||||
|
||||
if (state->data_header_sap[slot] == 0x3 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n UDP/IP Header Compression Data - Source: ");
|
||||
fprintf (stderr, "[%d]", dheader[3]);
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", dheader[2]);
|
||||
|
||||
sprintf ( state->dmr_lrrp[slot][1], "SRC [%d] DST [%d] ",
|
||||
dheader[3], dheader[2] );
|
||||
|
||||
state->dmr_lrrp_source[slot] = dheader[3];
|
||||
|
||||
}
|
||||
|
||||
if (state->data_header_sap[slot] == 0x5 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n ARP - Address Resolution Protocol ");
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF ) == 0xD && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Short Data - Defined - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF) == 0xE && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Short Data - Raw or Status/Precoded - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF ) == 0x1 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Response Packet - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0xF ) == 0x0 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Unified Data Transport - Source: ");
|
||||
fprintf (stderr, "[%d]", (dheader[5] <<16 ) + (dheader[6] << 8) + dheader[7] );
|
||||
fprintf (stderr, " Destination: ");
|
||||
fprintf (stderr, "[%d]", (dheader[2] <<16 ) + (dheader[3] <<8 ) + dheader[4] );
|
||||
}
|
||||
|
||||
if ( (state->data_header_format[slot] & 0x40) == 0x40 && state->data_p_head[slot] == 0) //check response req bit
|
||||
{
|
||||
fprintf (stderr, "\n Response Requested - ");
|
||||
fprintf (stderr, " Source:");
|
||||
fprintf (stderr, " [%d]", (dheader[2] <<16 ) + (dheader[3] << 8) + dheader[4] );
|
||||
fprintf (stderr, " Destination:");
|
||||
fprintf (stderr, " [%d]", (dheader[5] <<16 ) + (dheader[6] <<8 ) + dheader[7] );
|
||||
}
|
||||
|
||||
//if proprietary header was flagged by the last data header, then process data differently
|
||||
if (state->data_p_head[slot] == 1)
|
||||
{
|
||||
fprintf (stderr, "\n Proprietary Data Header: SAP %01X - Format %01X - MFID %02X",
|
||||
(dheader[0] & 0xF0) >> 4, dheader[0] & 0xF, dheader[1] );
|
||||
|
||||
state->data_p_head[slot] = 0;
|
||||
state->data_header_sap[slot] = 0; //reset this to zero so we don't trip the condition below
|
||||
state->data_block_counter[slot]++; //increment the counter since this counts against the data blocks
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (dheader[1] != 0) state->dmr_mfid = dheader[1];
|
||||
|
||||
//assign prop header pdu to 'superframe'
|
||||
uint8_t blocks = state->data_header_blocks[slot] - 1;
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i+(blocks*12)] = dheader[i];
|
||||
}
|
||||
}
|
||||
|
||||
//only set this flag after everything else is processed
|
||||
if (state->data_header_sap[slot] == 0x9 && state->data_p_head[slot] == 0)
|
||||
{
|
||||
fprintf (stderr, "\n Proprietary Packet Data Incoming ");
|
||||
state->data_p_head[slot] = 1; //flag that next data header will be a proprietary data header
|
||||
}
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
//assemble the blocks as they come in, shuffle them into the unified dmr_pdu_sf
|
||||
void dmr_block_assembler (dsd_opts * opts, dsd_state * state, uint8_t block_bytes[], uint8_t block_len, uint8_t databurst, uint8_t type)
|
||||
{
|
||||
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 slot = state->currentslot;
|
||||
int blocks;
|
||||
uint8_t blockcounter = state->data_block_counter[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
|
||||
|
||||
//TODO: CRC check on Header, Blocks and full frames as appropriate
|
||||
uint32_t CRCCorrect = 0;
|
||||
uint32_t CRCComputed = 0;
|
||||
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
|
||||
|
||||
if (type == 1) blocks = state->data_header_blocks[slot] - 1;
|
||||
if (type == 2) blocks = state->data_block_counter[slot];
|
||||
|
||||
//sanity check, setting block_len and block values to sane numbers in case of missing header, else could overload array (crash) or print out
|
||||
if (blocks < 1) blocks = 1; //changed blocks from uint8_t to int
|
||||
if (blocks > 8) blocks = 8;
|
||||
if (block_len == 0) block_len = 18;
|
||||
if (block_len > 24) block_len = 24;
|
||||
|
||||
//TODO: add CRC/FEC validation to each block and each confirmed data block as well - type 1
|
||||
if (type == 1)
|
||||
{
|
||||
//type 1 data block, shuffle method
|
||||
for (j = 0; j < blocks; j++) //6
|
||||
{
|
||||
for (i = 0; i < block_len; i++) //block_len
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i+block_len*j] = state->dmr_pdu_sf[slot][i+block_len*(j+1)];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < block_len; i++)
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i+(blocks*block_len)] = block_bytes[i];
|
||||
}
|
||||
//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, state->dmr_pdu_sf[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//type 2 - MBC header and MBC continuation blocks
|
||||
if (type == 2)
|
||||
{
|
||||
//sanity check (marginal signal, bad decodes, etc)
|
||||
if (state->data_block_counter[slot] > 8) state->data_block_counter[slot] = 8;
|
||||
|
||||
//Type 2 data block, additive method
|
||||
for (i = 0; i < block_len; i++)
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i+(blockcounter*block_len)] = block_bytes[i];
|
||||
}
|
||||
|
||||
memset (dmr_pdu_sf_bits, 0, sizeof(dmr_pdu_sf_bits));
|
||||
|
||||
lb = block_bytes[0] >> 7; //last block flag
|
||||
pf = (block_bytes[0] >> 6) & 1;
|
||||
|
||||
if (lb == 1) //last block arrived, time to send to cspdu decoder
|
||||
{
|
||||
for(i = 0, j = 0; i < 12*4; 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;
|
||||
}
|
||||
|
||||
//TODO: CRC check on Header and full frames as appropriate
|
||||
|
||||
//shim these values for now
|
||||
CRCCorrect = 1;
|
||||
IrrecoverableErrors = 0;
|
||||
|
||||
dmr_cspdu (opts, state, dmr_pdu_sf_bits, state->dmr_pdu_sf[slot], CRCCorrect, IrrecoverableErrors);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Full Super Frame Type 1 - Debug Output
|
||||
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);
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||
if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
//Full Super Frame MBC - Debug Output
|
||||
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);
|
||||
for (i = 0; i < ((blocks+1)*block_len); i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", state->dmr_pdu_sf[slot][i]);
|
||||
if (i == 11 || i == 23 || i == 35 || i == 47 || i == 59 || i == 71 || i == 83 || i == 95)
|
||||
{
|
||||
fprintf (stderr, "\n ");
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
state->data_block_counter[slot]++; //increment block counter
|
||||
|
||||
if (type == 2 && lb == 1)
|
||||
{
|
||||
state->data_block_counter[slot] = 0; //reset the block counter (MBCs)
|
||||
|
||||
//clear out unified pdu 'superframe' slot
|
||||
for (short int i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_pdu_sf[slot][i] = 0;
|
||||
}
|
||||
|
||||
state->data_block_crc_valid[slot][0] = 0; //Zero Out MBC Header Block CRC Valid
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
689
src/dmr_bs.c
689
src/dmr_bs.c
@@ -1,3 +1,11 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_bs.c
|
||||
* DMR BS Voice Handling and Data Gathering Routines - "DMR STEREO"
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
|
||||
@@ -7,32 +15,37 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, k, l, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25] = {0};
|
||||
char syncdata[48] = {0};
|
||||
//char cachdata[13] = {0};
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
char cc[4];
|
||||
unsigned char EmbeddedSignalling[16] = {0};
|
||||
int EmbeddedSignallingOk;
|
||||
unsigned int internalcolorcode;
|
||||
int internalslot;
|
||||
//redundancy check (carrier signal loss event)
|
||||
char redundancyA[36];
|
||||
char redundancyB[36];
|
||||
unsigned short int vc1;
|
||||
unsigned short int vc2;
|
||||
int cach_okay = 0;
|
||||
|
||||
//cach fec
|
||||
char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug
|
||||
int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23};
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
char m2[4][24];
|
||||
char m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
char EmbeddedSignalling[16];
|
||||
|
||||
uint8_t emb_ok = 0;
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
|
||||
uint8_t internalslot;
|
||||
uint8_t vc1;
|
||||
uint8_t vc2;
|
||||
|
||||
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof(dummy_bits));
|
||||
|
||||
//add time to mirror printFrameSync
|
||||
time_t now;
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
@@ -63,10 +76,21 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
short int loop = 1;
|
||||
short int skipcount = 0;
|
||||
|
||||
//cach
|
||||
char cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
|
||||
//cach tact bits
|
||||
uint8_t tact_bits[7];
|
||||
|
||||
//Run Loop while the getting is good
|
||||
while (loop == 1) {
|
||||
|
||||
// CACH
|
||||
internalslot = -1; //reset here so we know if this value is being set properly
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
@@ -77,30 +101,23 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
//decode and correct cach and compare
|
||||
cach_okay = 69;
|
||||
if ( Hamming_7_4_decode (cachdata) ) //see if we need to de-interleave this...probably do.
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
cach_okay = 1;
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
if (cach_okay == 1)
|
||||
|
||||
//disabled for dmr_cach testing
|
||||
tact_okay = 0;
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH Okay ");
|
||||
}
|
||||
if (cach_okay != 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH FEC Error %d", cach_okay);
|
||||
if (opts->aggressive_framesync == 1)
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state->currentslot = cachdata[1];
|
||||
internalslot = cachdata[1];
|
||||
|
||||
//this cach fec seems to work quite well, really helps on shaky signals
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
//Interleave Schedule
|
||||
@@ -115,6 +132,7 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+12] = dibit;
|
||||
redundancyA[i] = dibit;
|
||||
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -134,11 +152,9 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
// end redundancy test, set B to A
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
redundancyB[i] = redundancyA[i];
|
||||
}
|
||||
|
||||
//end redundancy test, set B to A
|
||||
memcpy (redundancyB, redundancyA, sizeof (redundancyA));
|
||||
|
||||
//Setup for Second AMBE Frame
|
||||
//Interleave Schedule
|
||||
@@ -162,90 +178,39 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//short int l = 0; //do I still use this?
|
||||
// signaling data or sync
|
||||
long long int late_entry_pi[24] = {0};
|
||||
short int m = 0;
|
||||
//signaling data or sync
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
|
||||
state->dmr_stereo_payload[i+66] = dibit;
|
||||
sync[i] = (dibit | 1) + 48; //how does this work again?
|
||||
|
||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
if (i < 4 || i > 19)
|
||||
{
|
||||
// fprintf(stderr, "\n EMB = ");
|
||||
EmbeddedSignalling[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
//fprintf (stderr, "%02b", dibit);
|
||||
EmbeddedSignalling[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
}
|
||||
|
||||
//Used for ProcessVoiceBurstSync
|
||||
//embedded link control
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => SYNC data */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0
|
||||
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
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => SYNC data */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sync[24] = 0;
|
||||
|
||||
EmbeddedSignallingOk = -1;
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling))
|
||||
{
|
||||
EmbeddedSignallingOk = 1;
|
||||
}
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
||||
|
||||
internalcolorcode = 69; //set so we know if this value is being set properly
|
||||
|
||||
if( EmbeddedSignallingOk == 1 ) //don't set on 1?
|
||||
{
|
||||
//state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
state->color_code_ok = EmbeddedSignallingOk;
|
||||
|
||||
//Power Indicator, not the other PI (header)
|
||||
state->PI = (unsigned int)EmbeddedSignalling[4];
|
||||
state->PI_ok = EmbeddedSignallingOk;
|
||||
|
||||
//Link Control Start Stop Indicator
|
||||
state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
state->LCSS_ok = EmbeddedSignallingOk;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
//fprintf (stderr, " %b", EmbeddedSignalling[i]);
|
||||
}
|
||||
|
||||
}
|
||||
//else skipcount++;
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
//fprintf (stderr, " %b", EmbeddedSignalling[i]);
|
||||
}
|
||||
}
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
//dibit = (dibit ^ 2);
|
||||
}
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -268,10 +233,6 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
//dibit = (dibit ^ 2);
|
||||
}
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -286,305 +247,137 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
//reset vc counters to 1 if new voice sync frame on each slot
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
|
||||
{
|
||||
if (internalslot == 0)
|
||||
{
|
||||
vc1 = 1;
|
||||
state->DMRvcL = 0; //reset here if internal sync forces reset
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
vc2 = 1;
|
||||
state->DMRvcR = 0; //reset here if internal sync forces reset
|
||||
}
|
||||
if (internalslot == 0) vc1 = 1;
|
||||
if (internalslot == 1) vc2 = 1;
|
||||
}
|
||||
|
||||
// if( strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)
|
||||
// {
|
||||
// fprintf (stderr,"%s ", getTime());
|
||||
// fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 1 \n");
|
||||
// goto SKIP;
|
||||
// }
|
||||
//
|
||||
// if( strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
|
||||
// {
|
||||
// fprintf (stderr,"%s ", getTime());
|
||||
// fprintf (stderr, " Sync: DMR TDMA Direct Mode TS 2 \n");
|
||||
// goto SKIP;
|
||||
// }
|
||||
|
||||
//check for sync pattern here after collected the rest of the payload, decide what to do with it
|
||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
||||
{
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
//constantly reset the vc counter to 1 each data frame in anticipation of new voice frame
|
||||
|
||||
vc1 = 1;
|
||||
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
//constantly reset the vc counter to 1 each data frame in anticipation of new voice frame
|
||||
|
||||
vc2 = 1;
|
||||
|
||||
}
|
||||
processDMRdata (opts, state);
|
||||
skipcount++; //after 2 data frames, drop back to getFrameSync and process subsequent data with processDMRdata
|
||||
goto SKIP;
|
||||
}
|
||||
|
||||
//find way to mitigate or correct coming back here after leaving in inverted signal
|
||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 && opts->inverted_dmr == 1)
|
||||
{
|
||||
dmr_data_sync (opts, state);
|
||||
skipcount++;
|
||||
goto SKIP;
|
||||
}
|
||||
|
||||
//extra check to see if we have missed a voice/data frame sync at this point and then exit if required
|
||||
if (1 == 1) //opts->aggressive_framesync
|
||||
{
|
||||
//extremely aggressive
|
||||
if ( vc1 > 7 || vc2 > 7 )
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//only play voice on no data sync
|
||||
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0)
|
||||
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure
|
||||
{
|
||||
|
||||
if (EmbeddedSignallingOk == 0)
|
||||
//check the embedded signalling, if bad at this point, we probably aren't quite in sync
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling)) emb_ok = 1;
|
||||
else emb_ok = 0;
|
||||
|
||||
//disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs
|
||||
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
||||
else if (emb_ok == 1)
|
||||
{
|
||||
//goto END;
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
skipcount = 0; //reset skip count if processing voice frames
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
|
||||
//simplifying things
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
uint8_t vc;
|
||||
if (internalslot == 0)
|
||||
{
|
||||
state->dmrburstL = 16; //use 16 for Voice?
|
||||
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR [SLOT1] slot2 | | DMRSTEREO | VC%d ",vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR [SLOT1] slot2 | | DMRSTEREO | VC%d ",vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (internalslot == 1)
|
||||
state->dmrburstL = 16;
|
||||
vc = vc1;
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 16; //use 16 for Voice?
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR slot1 [SLOT2] | | DMRSTEREO | VC%d ",vc2);
|
||||
if (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR slot1 [SLOT2] | | DMRSTEREO | VC%d ",vc2);
|
||||
if (state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues)
|
||||
state->dmrburstR = 16;
|
||||
vc = vc2;
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
||||
|
||||
if (internalslot == 0 && vc1 == 6)
|
||||
{
|
||||
//process voice burst
|
||||
ProcessVoiceBurstSync(opts, state);
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
}
|
||||
|
||||
if (internalslot == 1 && vc2 == 6) //presumably when full (and no sync issues)
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
{
|
||||
//process voice burst
|
||||
ProcessVoiceBurstSync(opts, state);
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
}
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
if (internalslot == 0 && vc1 == 6)
|
||||
{
|
||||
state->DMRvcL = 0;
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
if (state->payload_mi != 0 && state->payload_algid >= 0x21)
|
||||
{
|
||||
LFSR(state);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
// run alg refresh after vc6 ambe processing
|
||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state);
|
||||
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
{
|
||||
state->DMRvcR = 0;
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
if (state->payload_miR != 0 && state->payload_algidR >= 0x21)
|
||||
{
|
||||
LFSR(state);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
||||
|
||||
if (internalslot == 0)
|
||||
{
|
||||
vc1++;
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
vc2++;
|
||||
}
|
||||
//increment the vc counters
|
||||
if (internalslot == 0) vc1++;
|
||||
if (internalslot == 1) vc2++;
|
||||
|
||||
//reset err checks
|
||||
cach_err = 1;
|
||||
tact_okay = 0;
|
||||
emb_ok = 0;
|
||||
|
||||
}
|
||||
|
||||
// recalibrate center/umid/lmid, not sure this helps or does anything particularly in this case
|
||||
state->center = ((state->max) + (state->min)) / 2;
|
||||
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
|
||||
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
|
||||
|
||||
//Escape conditions to break the loop
|
||||
//7 seems optimal, allows for an extra frame each in case of late entry on dual voices
|
||||
if ( (vc1 > 7 && vc2 > 7) )
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
//14 probably allows a few more in case of a bit of jitter but eventually breaks loop (1 second?)
|
||||
if ( (vc1 > 14 || vc2 > 14) )
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
//earlier skip conditions teleport us here to process further skip conditions before restarting while loop
|
||||
SKIP:
|
||||
if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with processDMRdata
|
||||
if (skipcount > 2) //after 2 consecutive data frames, drop back to getFrameSync and process with dmr_data_sync
|
||||
{
|
||||
//set tests to all good so we don't get a bogus/redundant voice error
|
||||
cach_err = 0;
|
||||
tact_okay = 1;
|
||||
emb_ok = 1;
|
||||
goto END;
|
||||
}
|
||||
|
||||
@@ -595,26 +388,37 @@ void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
} // while loop
|
||||
//Teleport here on END condition, set or reset variables and return to look for new frame sync
|
||||
|
||||
END:
|
||||
state->dmr_stereo = 0;
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->errs2R = 0;
|
||||
state->errs2 = 0;
|
||||
|
||||
//if we have a cach err, then produce sync pattern/err message
|
||||
if (cach_okay != 1)
|
||||
//if we have a tact or emb err, then produce sync pattern/err message
|
||||
if (tact_okay != 1 || emb_ok != 1)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| ** VOICE CACH ERR ** ");
|
||||
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//run LFSR if either slot had an active MI in it.
|
||||
state->currentslot = 0;
|
||||
if (state->payload_algid >= 0x21) LFSR(state);
|
||||
state->currentslot = 1;
|
||||
if (state->payload_algidR >= 0x21) LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
//run LFSR if either slot had an active MI in it.
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -624,22 +428,28 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, k, l, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
char m2[4][24];
|
||||
char m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
char cc[4];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
unsigned int EmbeddedSignallingOk;
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
|
||||
//cach fec
|
||||
char cachdata[25] = {0}; //increased from 24 to 25 to see if this fixes ubuntu 32 bug
|
||||
int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23};
|
||||
|
||||
char cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
//add time to mirror printFrameSync
|
||||
time_t now;
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
@@ -678,27 +488,24 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
//decode and correct cach and compare
|
||||
int cach_okay = 69;
|
||||
if ( Hamming_7_4_decode (cachdata) ) //see if we need to de-interleave this...probably do.
|
||||
//cach tact bits
|
||||
uint8_t tact_bits[7];
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
cach_okay = 1;
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
if (cach_okay == 1)
|
||||
|
||||
//decode and correct tact and compare
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH Okay ");
|
||||
}
|
||||
if (cach_okay != 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH FEC Error %d", cach_okay);
|
||||
if (opts->aggressive_framesync == 1)
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state->currentslot = cachdata[1];
|
||||
state->currentslot = tact_bits[1];
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
|
||||
@@ -751,12 +558,8 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
//this method seems to work to make sure we aren't in a data sync especially when inverted signal
|
||||
//consider only testing this when inverted signal if this causes issues with sync later on
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0)
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0) goto END;
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
@@ -795,95 +598,65 @@ void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
|
||||
}
|
||||
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) )
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
}
|
||||
if ( (state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) )
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code);
|
||||
|
||||
state->DMRvcL = 0;
|
||||
state->DMRvcR = 0;
|
||||
dmr_alg_reset (opts, state);
|
||||
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
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);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode
|
||||
END:
|
||||
//if we have a cach err, then produce sync pattern/err message
|
||||
if (cach_okay != 1)
|
||||
//if we have a tact err, then produce sync pattern/err message
|
||||
if (tact_okay != 1)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| ** VOICE CACH ERR ** ");
|
||||
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//run LFSR if either slot had an active MI in it.
|
||||
state->currentslot = 0;
|
||||
if (state->payload_algid >= 0x21) LFSR(state);
|
||||
state->currentslot = 1;
|
||||
if (state->payload_algidR >= 0x21) LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
LFSR(state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
586
src/dmr_csbk.c
Normal file
586
src/dmr_csbk.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_csbk.c
|
||||
* DMR Control Signal Data PDU (CSBK, MBC, UDT) Handler and Related Functions
|
||||
*
|
||||
* Portions of Connect+ code reworked from Boatbod OP25
|
||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||
*
|
||||
* Portions of Capacity+ code reworked from Eric Cottrell
|
||||
* Source: https://github.com/LinuxSheeple-E/dsd/blob/Feature/DMRECC/dmr_csbk.c
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//function for handling Control Signalling PDUs (CSBK, MBC, UDT) messages
|
||||
void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8_t cs_pdu[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||
{
|
||||
|
||||
int csbk_lb = 0;
|
||||
int csbk_pf = 0;
|
||||
int csbk_o = 0;
|
||||
int csbk_fid = 0;
|
||||
uint64_t csbk_data = 0;
|
||||
int csbk = 0;
|
||||
|
||||
if(IrrecoverableErrors == 0 && CRCCorrect == 1)
|
||||
{
|
||||
|
||||
csbk_lb = ( (cs_pdu[0] & 0x80) >> 7 );
|
||||
csbk_pf = ( (cs_pdu[0] & 0x40) >> 6 );
|
||||
csbk_o = cs_pdu[0] & 0x3F;
|
||||
csbk_fid = cs_pdu[1]; //feature set id
|
||||
csbk_pf = ( (cs_pdu[1] & 0x80) >> 7);
|
||||
csbk = ((cs_pdu[0] & 0x3F) << 8) | cs_pdu[1]; //opcode and fid combo set
|
||||
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
if (csbk_fid != 0) state->dmr_mfid = csbk_fid;
|
||||
|
||||
//TIII standard with fid of 0 - (opcodes in decimal)
|
||||
if (0 == 0) //standard feature set for TIII //csbk_fid == 0
|
||||
{
|
||||
|
||||
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
//7.1.1.1.1 Channel Grant CSBK/MBC PDU
|
||||
if (csbk_o > 47 && csbk_o < 53 )
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
long int freq = 0;
|
||||
|
||||
//all of these messages share the same format (thankfully)
|
||||
if (csbk_o == 48) fprintf (stderr, " Private Voice Channel Grant (PV_GRANT)");
|
||||
if (csbk_o == 49) fprintf (stderr, " Talkgroup Voice Channel Grant (TV_GRANT)");
|
||||
if (csbk_o == 50) fprintf (stderr, " Private Broadcast Voice Channel Grant (BTV_GRANT)");
|
||||
if (csbk_o == 51) fprintf (stderr, " Private Data Channel Grant: Single Item (PD_GRANT)");
|
||||
if (csbk_o == 52) fprintf (stderr, " Talkgroup Data Channel Grant: Single Item (TD_GRANT)");
|
||||
|
||||
//Logical Physical Channel Number
|
||||
uint16_t lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 12);
|
||||
if (lpchannum == 0) fprintf (stderr, " - Invalid Channel"); //invalid channel, not sure why this would even be transmitted
|
||||
else if (lpchannum == 0xFFF) fprintf (stderr, " - Absolute"); //This is from an MBC, signalling an absolute and not a logical
|
||||
else fprintf (stderr, " - Logical");
|
||||
|
||||
//LCN conveyed here is the tdma timeslot variety, and not the RF frequency variety
|
||||
uint8_t lcn = cs_pdu_bits[28];
|
||||
//the next three bits can have different meanings depending on which item above for context
|
||||
uint8_t st1 = cs_pdu_bits[29]; //late_entry, hi_rate
|
||||
uint8_t st2 = cs_pdu_bits[30]; //emergency
|
||||
uint8_t st3 = cs_pdu_bits[31]; //offset, call direction
|
||||
//target and source are always the same bits
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " CHAN [%03X][%04d] - LCN/TS [%d] - Target [%08d] - Source [%08d]", lpchannum, lpchannum, lcn, target, source);
|
||||
if (st2) fprintf (stderr, " Emergency");
|
||||
|
||||
if (lpchannum == 0xFFF) //This is from an MBC, signalling an absolute and not a logical
|
||||
{
|
||||
|
||||
//7.1.1.1.2 Channel Grant Absolute Parameters CG_AP appended MBC PDU
|
||||
uint8_t mbc_lb = cs_pdu_bits[96]; //
|
||||
uint8_t mbc_pf = cs_pdu_bits[97];
|
||||
uint8_t mbc_csbko = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[98], 6);
|
||||
uint8_t mbc_res = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[104], 4);
|
||||
uint8_t mbc_cc = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[108], 4);
|
||||
uint8_t mbc_cdeftype = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[112], 4); //see 7.2.19.7 = 0 for channel parms, 1 through FFFF reserved
|
||||
uint8_t mbc_res2 = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[116], 2);
|
||||
uint64_t mbc_cdefparms = (uint64_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 58); //see 7.2.19.7.1
|
||||
|
||||
//this is how you read the 58 parm bits according to the appendix 7.2.19.7.1
|
||||
if (mbc_cdeftype == 0) //if 0, then absolute channel parms
|
||||
{
|
||||
uint16_t mbc_lpchannum = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[118], 12);
|
||||
uint16_t mbc_abs_tx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[130], 10);
|
||||
uint16_t mbc_abs_tx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[140], 13);
|
||||
uint16_t mbc_abs_rx_int = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[153], 10);
|
||||
uint16_t mbc_abs_rx_step = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[163], 13);
|
||||
|
||||
//tx_int (Mhz) + (tx_step * 125) = tx_freq
|
||||
//rx_int (Mhz) + (rx_step * 125) = rx_freq
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " ABS-CHAN [%03X][%04d] - RX INT [%d][%X] - RX STEP [%d][%X]", mbc_lpchannum, mbc_lpchannum, mbc_abs_rx_int, mbc_abs_rx_int, mbc_abs_rx_step, mbc_abs_rx_step );
|
||||
//DOULBE CHECK APPENDIX C - C.1.1.2 Fixed Channel Plan for accurate information (found it after figuring out calc, so might be worth double checking)
|
||||
//The Frequency we want to tune is the RX Frequency
|
||||
freq = (mbc_abs_rx_int * 1000000 ) + (mbc_abs_rx_step * 125);
|
||||
//tx_freq = (mbc_abs_tx_int * 1000000 ) + (mbc_abs_tx_step * 125);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//print frequency from absolute
|
||||
if (freq != 0 && lpchannum == 0xFFF) fprintf (stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
|
||||
//run external channel map function on logical
|
||||
if (lpchannum != 0 && lpchannum != 0xFFF)
|
||||
{
|
||||
freq = state->trunk_chan_map[lpchannum];
|
||||
(stderr, "\n Frequency [%.6lf] MHz", (double)freq/1000000);
|
||||
}
|
||||
|
||||
//if not a data channel grant (only tuning to voice channel grants)
|
||||
if (csbk_o < 51) //48, 49, 50 are voice grants, 51 and 52 are data grants
|
||||
{
|
||||
//shim in chan map 0 as the cc frequency, user will need to specify it in the channel map file
|
||||
if (state->p25_cc_freq != 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
|
||||
//shim in here for ncurses freq display when not trunking (playback, not live)
|
||||
if (opts->p25_trunk == 0 && freq != 0)
|
||||
{
|
||||
//just set to both for now, could go on tslot later
|
||||
state->p25_vc_freq[0] = freq;
|
||||
state->p25_vc_freq[1] = freq;
|
||||
}
|
||||
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == target)
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0))
|
||||
{
|
||||
if (freq != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
SetModulation(opts->rigctl_sockfd, 12500); //bw depends on system strength more than anything, 12.5 should be safe for DMR
|
||||
SetFreq(opts->rigctl_sockfd, freq); //minus one because our index starts at zero
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
}
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, freq);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = freq;
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Move
|
||||
if (csbk_o == 57)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Move (C_MOVE) (TODO)");
|
||||
}
|
||||
|
||||
//Aloha
|
||||
if (csbk_o == 25)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint8_t reserved = cs_pdu_bits[16];
|
||||
uint8_t tsccas = cs_pdu_bits[17];
|
||||
uint8_t sync = cs_pdu_bits[18];
|
||||
uint8_t version = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[19], 3); //Document Version Control
|
||||
uint8_t offset = cs_pdu_bits[22]; //0-TSCC uses aligned timing; 1-TSCC uses offset timing
|
||||
uint8_t active = cs_pdu_bits[23]; //Active_Connection
|
||||
uint8_t mask = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[24], 5);
|
||||
uint8_t sf = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[29], 2); //service function
|
||||
uint8_t nrandwait = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[31], 4);
|
||||
uint8_t regreq = cs_pdu_bits[35];
|
||||
uint8_t backoff = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[36], 4);
|
||||
|
||||
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
|
||||
uint16_t net = 0;
|
||||
uint16_t site = 0;
|
||||
char model_str[8];
|
||||
sprintf (model_str, "%s", " ");
|
||||
if (model == 0) //Tiny
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 9);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[51], 3);
|
||||
sprintf (model_str, "%s", "Tiny");
|
||||
}
|
||||
else if (model == 1) //Small
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 7);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[49], 5);
|
||||
sprintf (model_str, "%s", "Small");
|
||||
}
|
||||
else if (model == 2) //Large
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 4);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[46], 8);
|
||||
sprintf (model_str, "%s", "Large");
|
||||
}
|
||||
else if (model == 3) //Huge
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 2);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[44], 10);
|
||||
sprintf (model_str, "%s", "Huge");
|
||||
}
|
||||
|
||||
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
fprintf (stderr, " C_ALOHA_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d \n Reg Req: %d V: %d MS: %d", model_str, net, site, par, regreq, version, target);
|
||||
//fprintf (stderr, " Sys ID Code: [%04X]", sysidcode);
|
||||
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
|
||||
}
|
||||
|
||||
//P_CLEAR
|
||||
if (csbk_o == 46)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Clear (P_CLEAR) (TODO)");
|
||||
}
|
||||
|
||||
//(P_PROTECT) - Could be a useful way of determining who is on the current timeslot p_kind 2
|
||||
if (csbk_o == 47)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Protect (P_PROTECT) -");
|
||||
uint16_t reserved = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 12);
|
||||
uint8_t p_kind = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[28], 3);
|
||||
uint8_t gi = cs_pdu_bits[31];
|
||||
uint32_t target = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[32], 24);
|
||||
uint32_t source = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
|
||||
if (p_kind == 0) fprintf (stderr, " Disable Target PTT (DIS_PTT)");
|
||||
if (p_kind == 1) fprintf (stderr, " Enable Target PTT (EN_PTT)");
|
||||
if (p_kind == 2) fprintf (stderr, " Private Call (ILLEGALLY_PARKED)");
|
||||
if (p_kind == 3) fprintf (stderr, " Enable Target MS PTT(EN_PTT_ONE_MS)");//EN_PTT_ONE_MS
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Target [%08d] - Source [%08d]", target, source);
|
||||
|
||||
//experimental, but this may work work if we stay on this channel
|
||||
//may be reversed considering we won't know exactly who is going to answer first
|
||||
//only good for an initial protect clear all as well
|
||||
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
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Announcements (C_BCAST)"); //site it, vote for etc etc
|
||||
uint8_t a_type = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[16], 5);
|
||||
if (a_type == 0) fprintf (stderr, " Announce/Withdraw TSCC (Ann_WD_TSCC)");
|
||||
if (a_type == 1) fprintf (stderr, " Specify Call Timer Parameters (CallTimer_Parms)");
|
||||
if (a_type == 2) fprintf (stderr, " Vote Now Advice (Vote_Now)");
|
||||
if (a_type == 3) fprintf (stderr, " Broadcast Local Time (Local_Time)");
|
||||
if (a_type == 4) fprintf (stderr, " Mass Registration (MassReg)");
|
||||
if (a_type == 5) fprintf (stderr, " Announce Logical Channel/Frequency Relationship (Chan_Freq)");
|
||||
if (a_type == 6) fprintf (stderr, " Adjacent Site Information (Adjacent_Site)");
|
||||
if (a_type == 7) fprintf (stderr, " General Site Parameters (Gen_Site_Params)");
|
||||
if (a_type > 7 && a_type < 0x1E) fprintf (stderr, " Reserved %02X", a_type);
|
||||
if (a_type == 0x1E || a_type == 0x1F) fprintf (stderr, " Manufacturer Specific %02X", a_type);
|
||||
|
||||
//sysidcode, probably would have been easier to make this its own external function
|
||||
uint8_t model = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 2);
|
||||
uint16_t net = 0;
|
||||
uint16_t site = 0;
|
||||
char model_str[8];
|
||||
sprintf (model_str, "%s", " ");
|
||||
|
||||
if (model == 0) //Tiny
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 9);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[51], 3);
|
||||
sprintf (model_str, "%s", "Tiny");
|
||||
}
|
||||
else if (model == 1) //Small
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 7);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[49], 5);
|
||||
sprintf (model_str, "%s", "Small");
|
||||
}
|
||||
else if (model == 2) //Large
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 4);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[46], 8);
|
||||
sprintf (model_str, "%s", "Large");
|
||||
}
|
||||
else if (model == 3) //Huge
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[42], 2);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[44], 10);
|
||||
sprintf (model_str, "%s", "Huge");
|
||||
}
|
||||
|
||||
uint8_t par = (uint8_t)ConvertBitIntoBytes(&cs_pdu_bits[54], 2);
|
||||
uint32_t parms2 = (uint32_t)ConvertBitIntoBytes(&cs_pdu_bits[56], 24);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_BCAST_SYS_PARMS - %s - Net ID: %d Site ID: %d Par: %d ", model_str, net, site, par);
|
||||
uint16_t syscode = (uint16_t)ConvertBitIntoBytes(&cs_pdu_bits[40], 16);
|
||||
//fprintf (stderr, "\n SYSCODE: %016b", syscode);
|
||||
|
||||
}
|
||||
|
||||
if (csbk == 28)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_AHOY (TODO)");
|
||||
}
|
||||
|
||||
if (csbk == 42)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " P_MAINT (TODO)");
|
||||
}
|
||||
|
||||
if (csbk == 30)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_ACKVIT (TODO)");
|
||||
}
|
||||
|
||||
if (csbk == 31)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " C_RAND (TODO)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Capacity+ Section
|
||||
if (csbk_fid == 0x10)
|
||||
{
|
||||
//will need to ponder the best way to do trunking rules for this
|
||||
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 ch[8]; //one bit per channel
|
||||
uint8_t tg = 0;
|
||||
uint32_t tghex = 0; //combined all tgs for debug
|
||||
int i, k;
|
||||
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];
|
||||
}
|
||||
|
||||
fprintf (stderr, " Capacity Plus Channel Status - Rest Channel %d", 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);
|
||||
fprintf (stderr, " %03d ", tg);
|
||||
k++;
|
||||
|
||||
}
|
||||
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_sub, "%s", "Cap+ ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
//Connect+ Section
|
||||
if (csbk_fid == 0x06)
|
||||
{
|
||||
if (csbk_o == 0x01)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint8_t nb1 = cs_pdu[2] & 0x3F;
|
||||
uint8_t nb2 = cs_pdu[3] & 0x3F;
|
||||
uint8_t nb3 = cs_pdu[4] & 0x3F;
|
||||
uint8_t nb4 = cs_pdu[5] & 0x3F;
|
||||
uint8_t nb5 = cs_pdu[6] & 0x3F;
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Neighbors\n");
|
||||
fprintf (stderr, " NB1(%02d), NB2(%02d), NB3(%02d), NB4(%02d), NB5(%02d)", nb1, nb2, nb3, nb4, nb5);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x03)
|
||||
{
|
||||
//shim in chan map 0 as the cc frequency, user will need to specify it in the channel map file
|
||||
if (state->p25_cc_freq != 0 && state->trunk_chan_map[0] != 0) state->p25_cc_freq = state->trunk_chan_map[0];
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 );
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Voice Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
// state->dmr_vc_lcn = lcn;
|
||||
// state->dmr_vc_lsn = lcn * (tslot+1);
|
||||
|
||||
//shim in here for ncurses freq display when not trunking (playback, not live)
|
||||
if (opts->p25_trunk == 0 && state->trunk_chan_map[lcn] != 0)
|
||||
{
|
||||
//just set to both for now, could go on tslot later
|
||||
state->p25_vc_freq[0] = state->trunk_chan_map[lcn];
|
||||
state->p25_vc_freq[1] = state->trunk_chan_map[lcn];
|
||||
}
|
||||
|
||||
char mode[8]; //allow, block, digital, enc, etc
|
||||
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
if (state->group_array[i].groupNumber == grpAddr)
|
||||
{
|
||||
fprintf (stderr, " [%s]", state->group_array[i].groupName);
|
||||
strcpy (mode, state->group_array[i].groupMode);
|
||||
}
|
||||
}
|
||||
|
||||
//need channel map frequencies and stuff, also way to figure out control channel frequency? (channel 0 from channel map?)
|
||||
if (state->p25_cc_freq != 0 && opts->p25_trunk == 1 && (strcmp(mode, "DE") != 0))
|
||||
{
|
||||
if (state->trunk_lcn_freq[lcn] != 0) //if we have a valid frequency
|
||||
{
|
||||
//RIGCTL
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
SetModulation(opts->rigctl_sockfd, 12500); //bw depends on system strength more than anything, 12.5 should be safe for DMR
|
||||
SetFreq(opts->rigctl_sockfd, state->trunk_chan_map[lcn]); //minus one because our index starts at zero
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn];
|
||||
opts->p25_is_tuned = 1; //set to 1 to set as currently tuned so we don't keep tuning nonstop
|
||||
}
|
||||
}
|
||||
|
||||
//rtl_udp
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
rtl_udp_tune (opts, state, state->trunk_chan_map[lcn]);
|
||||
state->p25_vc_freq[0] = state->p25_vc_freq[1] = state->trunk_chan_map[lcn];
|
||||
opts->p25_is_tuned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (csbk_o == 0x06)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ;
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 );
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Data Channel Grant\n");
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
if (csbk_o == 0x0C)
|
||||
{
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
uint32_t srcAddr = ( (cs_pdu[2] << 16) + (cs_pdu[3] << 8) + cs_pdu[4] );
|
||||
uint32_t grpAddr = ( (cs_pdu[5] << 16) + (cs_pdu[6] << 8) + cs_pdu[7] );
|
||||
uint8_t lcn = ( (cs_pdu[8] & 0xF0 ) >> 4 ) ; ////extract(csbk, 64, 68); //double check these?
|
||||
uint8_t tslot = ( (cs_pdu[8] & 0x08 ) >> 3 ); //csbk[68];
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Connect Plus Terminate Channel Grant\n"); //Data only shows a srcAddr??
|
||||
fprintf (stderr, " srcAddr(%8d), grpAddr(%8d), LCN(%d), TS(%d)",srcAddr, grpAddr, lcn, tslot);
|
||||
state->dmr_mfid = 0x06;
|
||||
sprintf(state->dmr_branding_sub, "Con+ ");
|
||||
}
|
||||
|
||||
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_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_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_sub, "Con+ ");
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
END:
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
396
src/dmr_data.c
396
src/dmr_data.c
@@ -18,35 +18,32 @@
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, dibit;
|
||||
int *dibit_p;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
char cachdata[25] = {0};
|
||||
char cc[5] = {0};
|
||||
char ccAscii[5] = {0};
|
||||
char bursttype[5];
|
||||
unsigned int burst;
|
||||
char info[196];
|
||||
char cachdata[25];
|
||||
|
||||
char bursttype[5];
|
||||
uint8_t burst;
|
||||
char info[196];
|
||||
unsigned char SlotType[20];
|
||||
unsigned int SlotTypeOk;
|
||||
int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23};
|
||||
uint8_t cach_err = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
char syncbits[49];
|
||||
char cachbits[25];
|
||||
int k;
|
||||
#endif
|
||||
|
||||
ccAscii[4] = 0;
|
||||
bursttype[4] = 0;
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
|
||||
dibit_p = state->dmr_payload_p - 90;
|
||||
// CACH
|
||||
|
||||
//collect cach and de-interleave
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
@@ -65,67 +62,34 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//decode and correct cach and compare
|
||||
int cach_okay = 69;
|
||||
if ( Hamming_7_4_decode (cachdata) ) //is now de-interleaved appropriately
|
||||
//seperate tact bits from cach
|
||||
uint8_t tact_bits[7];
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
cach_okay = 1;
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
if (cach_okay == 1)
|
||||
|
||||
//run hamming on tact bits
|
||||
int cach_okay = -1;
|
||||
if ( Hamming_7_4_decode (tact_bits) ) cach_okay = 1;
|
||||
else
|
||||
{
|
||||
//fprintf (stderr, "CACH Okay ");
|
||||
}
|
||||
if (cach_okay != 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH FEC Error %d", cach_okay);
|
||||
if (opts->aggressive_framesync == 1) //may not worry about it on data
|
||||
cach_okay = -1;
|
||||
if (opts->aggressive_framesync == 2)
|
||||
{
|
||||
SlotTypeOk = 0;
|
||||
goto END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state->currentslot = cachdata[1];
|
||||
state->currentslot = tact_bits[1];
|
||||
|
||||
//minor bugfix for MSData when MSData has accumulated data blocks
|
||||
//(i.e. data header and 1/2 rate data), force all data into slot 0
|
||||
//in the future, maybe we will remove the hard set on this
|
||||
if (state->dmr_ms_mode == 1)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
}
|
||||
|
||||
if (state->currentslot == 0 && state->dmr_ms_mode == 0)
|
||||
{
|
||||
state->slot1light[0] = '[';
|
||||
state->slot1light[6] = ']';
|
||||
state->slot2light[0] = ' ';
|
||||
state->slot2light[6] = ' ';
|
||||
}
|
||||
//else
|
||||
if (state->currentslot == 1 && state->dmr_ms_mode == 0)
|
||||
{
|
||||
state->slot2light[0] = '[';
|
||||
state->slot2light[6] = ']';
|
||||
state->slot1light[0] = ' ';
|
||||
state->slot1light[6] = ' ';
|
||||
}
|
||||
//end correct cach and set slot
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
fprintf(stderr, "%s ", cachbits);
|
||||
#endif
|
||||
//trellis bits
|
||||
unsigned char trellisdibits[98];
|
||||
// Current slot - First half - Data Payload - 1st part
|
||||
for (i = 0; i < 49; i++)
|
||||
{
|
||||
@@ -139,7 +103,6 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i+12];
|
||||
}
|
||||
trellisdibits[i] = dibit;
|
||||
info[2*i] = (1 & (dibit >> 1)); // bit 1
|
||||
info[(2*i)+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
@@ -153,10 +116,9 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (state->dmr_stereo == 1)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[61]; //61, not i+61
|
||||
dibit = (int)state->dmr_stereo_payload[61];
|
||||
}
|
||||
cc[0] = (1 & (dibit >> 1)); // bit 1
|
||||
cc[1] = (1 & dibit); // bit 0
|
||||
|
||||
SlotType[0] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[1] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -170,17 +132,10 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[62];
|
||||
}
|
||||
cc[2] = (1 & (dibit >> 1)); // bit 1
|
||||
cc[3] = (1 & dibit); // bit 0
|
||||
|
||||
SlotType[2] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[3] = (1 & dibit); // bit 0
|
||||
|
||||
ccAscii[0] = cc[0] + '0';
|
||||
ccAscii[1] = cc[1] + '0';
|
||||
ccAscii[2] = cc[2] + '0';
|
||||
ccAscii[3] = cc[3] + '0';
|
||||
ccAscii[4] = cc[4] + '\0';
|
||||
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
@@ -189,7 +144,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (state->dmr_stereo == 1) //state
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[63]; //(int)
|
||||
dibit = (int)state->dmr_stereo_payload[63];
|
||||
}
|
||||
|
||||
SlotType[4] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -203,7 +158,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (state->dmr_stereo == 1) //state
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[64]; //(int)
|
||||
dibit = (int)state->dmr_stereo_payload[64];
|
||||
}
|
||||
|
||||
SlotType[6] = (1 & (dibit >> 1)); // bit 1
|
||||
@@ -223,7 +178,7 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
SlotType[8] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[9] = (1 & dibit); // bit 0
|
||||
|
||||
// signalling data or sync
|
||||
// signaling data or sync
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
@@ -239,32 +194,19 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
syncdata[2*i] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
|
||||
|
||||
}
|
||||
sync[24] = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
syncbits[k] = syncdata[(k*2)] + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = syncdata[(k*2)+1] + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
fprintf(stderr, "%s ", syncbits);
|
||||
#endif
|
||||
|
||||
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) )//|| (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
|
||||
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) )
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
}
|
||||
}
|
||||
@@ -273,15 +215,17 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
sprintf(state->slot1light, "[sLoT1]");
|
||||
sprintf(state->slot2light, "[DMODE]");
|
||||
}
|
||||
|
||||
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
sprintf(state->slot1light, "[DMODE]");
|
||||
sprintf(state->slot2light, "[sLoT2]");
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1 && state->dmr_ms_mode == 0)
|
||||
if (state->dmr_ms_mode == 0)
|
||||
{
|
||||
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
}
|
||||
@@ -289,283 +233,85 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
// Slot type - Second part - Parity bit
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method
|
||||
if (state->dmr_stereo == 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
//dibit = (dibit ^ 2);
|
||||
}
|
||||
if (state->dmr_stereo == 1)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i+90]; //double checked these i+ values make sure we are on the right ones
|
||||
dibit = (int)state->dmr_stereo_payload[i+90];
|
||||
}
|
||||
SlotType[(i*2) + 10] = (1 & (dibit >> 1)); // bit 1
|
||||
SlotType[(i*2) + 11] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
/* Check and correct the SlotType (apply Golay(20,8) FEC check) */
|
||||
|
||||
|
||||
// golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors
|
||||
if( Golay_20_8_decode(SlotType) )
|
||||
{
|
||||
SlotTypeOk = 1;
|
||||
//fprintf (stderr, "Slot Okay ");
|
||||
}
|
||||
if( Golay_20_8_decode(SlotType) ) SlotTypeOk = 1;
|
||||
else
|
||||
{
|
||||
|
||||
SlotTypeOk = -1;
|
||||
if (opts->aggressive_framesync == 1)
|
||||
{
|
||||
SlotTypeOk = 0;
|
||||
goto END;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Slot Type parity checked => Fill the color code */
|
||||
state->color_code = (SlotType[0] << 3) + (SlotType[1] << 2) +(SlotType[2] << 1) + (SlotType[3] << 0);
|
||||
state->color_code_ok = SlotTypeOk;
|
||||
|
||||
/* Reconstitute the burst type */
|
||||
//consider assigning this only when slottypeok or similar check passes, eliminate bad burst types from decoding randomly
|
||||
burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dmrburstL = burst;
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmrburstR = burst;
|
||||
}
|
||||
//not sure why I still have two variables for this, need to look and see what state->color_code still ties into
|
||||
if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
|
||||
|
||||
/* Reconstitute the burst type */
|
||||
bursttype[0] = SlotType[4] + '0';
|
||||
bursttype[1] = SlotType[5] + '0';
|
||||
bursttype[2] = SlotType[6] + '0';
|
||||
bursttype[3] = SlotType[7] + '0';
|
||||
bursttype[4] = '\0';
|
||||
burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
|
||||
if (state->currentslot == 0) state->dmrburstL = burst;
|
||||
if (state->currentslot == 1) state->dmrburstR = burst;
|
||||
|
||||
if (strcmp (bursttype, "0000") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " PI Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0001") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " VOICE LC ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0010") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " TLC ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0011") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " CSBK ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0100") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " MBC Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0101") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " MBC ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0110") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " DATA Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0111") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " RATE 1/2 DATA");
|
||||
}
|
||||
else if (strcmp (bursttype, "1000") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " RATE 3/4 DATA");
|
||||
}
|
||||
else if (strcmp (bursttype, "1001") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " Slot idle ");
|
||||
}
|
||||
else if (strcmp (bursttype, "1010") == 0)
|
||||
{
|
||||
sprintf(state->fsubtype, " Rate 1 DATA ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->fsubtype, " ");
|
||||
}
|
||||
|
||||
// Current slot - First half - Data Payload - 1st part
|
||||
//trellis
|
||||
// Current slot - Second Half - Data Payload - 2nd part
|
||||
for (i = 0; i < 49; i++)
|
||||
{
|
||||
if (state->dmr_stereo == 0) //only get dibits if not using dmr_stereo method
|
||||
if (state->dmr_stereo == 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
//dibit = (dibit ^ 2);
|
||||
}
|
||||
|
||||
if (state->dmr_stereo == 1)
|
||||
{
|
||||
dibit = (int)state->dmr_stereo_payload[i+95]; //double checked these i+ values make sure we are on the right ones
|
||||
dibit = (int)state->dmr_stereo_payload[i+95];
|
||||
}
|
||||
trellisdibits[i+49] = dibit;
|
||||
|
||||
info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1
|
||||
info[(2*i) + 99] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)info, burst);
|
||||
|
||||
// Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit)
|
||||
if (state->dmr_stereo == 0)
|
||||
//don't run cach on simplex or mono
|
||||
if (state->dmr_ms_mode == 0 || opts->dmr_mono == 0)
|
||||
{
|
||||
skipDibit (opts, state, 12 + 49 + 5);
|
||||
}
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
/* Print the color code */
|
||||
//if (burst == 0b1001 && state->color_code_ok) //only print on idle for data types, otherwise prints on voice frames.
|
||||
if (SlotTypeOk == 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
//state->dmr_color_code = state->color_code;
|
||||
}
|
||||
else fprintf(stderr, "| ");
|
||||
//ending line break
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
//if(state->color_code_ok) fprintf(stderr, "(OK) |");
|
||||
if(state->color_code_ok) fprintf(stderr, "| (CRC OK ) |"); //add line break
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, "| (CRC ERR) |");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
//fprintf (stderr, "\n"); //print line break
|
||||
if (strcmp (state->fsubtype, " ") == 0)
|
||||
{
|
||||
//fprintf(stderr, " Unknown burst type: %s", bursttype);
|
||||
fprintf(stderr, " Unknown");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s", state->fsubtype);
|
||||
}
|
||||
}
|
||||
|
||||
switch(burst)
|
||||
{
|
||||
/* Burst = PI header */
|
||||
case 0b0000:
|
||||
{
|
||||
ProcessDmrPIHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = Voice LC header */
|
||||
case 0b0001:
|
||||
{
|
||||
/* Extract data from Voice LC Header */
|
||||
ProcessDmrVoiceLcHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = TLC */
|
||||
case 0b0010:
|
||||
{
|
||||
//Not sure if I really care about this in the context of what it shows
|
||||
ProcessDmrTerminaisonLC(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = CSBK */
|
||||
case 0b0011:
|
||||
{
|
||||
//going to disable until I can find more useful info to present
|
||||
ProcessCSBK(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = MBC Header */
|
||||
case 0b0100:
|
||||
{
|
||||
ProcessMBChData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = MBC Continuation*/
|
||||
case 0b0101:
|
||||
{
|
||||
ProcessMBCData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = DATA Header */
|
||||
case 0b0110:
|
||||
{
|
||||
ProcessDataData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = RATE 1/2 DATA */
|
||||
case 0b0111:
|
||||
{
|
||||
Process12Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = RATE 3/4 DATA */
|
||||
case 0b1000:
|
||||
{
|
||||
//need to keep working on improving the trellis decode, but is partially viable now
|
||||
Process34Data(opts, state, trellisdibits, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = Slot idle */
|
||||
case 0b1001:
|
||||
{
|
||||
if(state->color_code_ok && state->dmr_stereo == 0) state->dmr_color_code = state->color_code; //try setting this on idle if crc ok
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = Rate 1 DATA */
|
||||
case 0b1010:
|
||||
{
|
||||
Process1Data(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = Unified Single Block DATA */
|
||||
case 0b1101:
|
||||
{
|
||||
ProcessUnifiedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Default */
|
||||
default:
|
||||
{
|
||||
/* Nothing to do */
|
||||
ProcessReservedData(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
} /* End switch(burst) */
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
END:
|
||||
if (SlotTypeOk == 0 || cach_okay != 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| ** CACH or Burst Type FEC ERR ** ");
|
||||
fprintf (stderr, "| CACH/Burst FEC ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
} /* End processDMRdata() */
|
||||
// Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit)
|
||||
if (state->dmr_stereo == 0)
|
||||
{
|
||||
skipDibit (opts, state, 12 + 49 + 5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
446
src/dmr_dburst.c
Normal file
446
src/dmr_dburst.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_dburst.c
|
||||
* DMR Data Burst Handling and related BPTC/FEC/CRC Functions
|
||||
*
|
||||
* Portions of BPTC/FEC/CRC code from LouisErigHerve
|
||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
//TODO: CRC9 on confirmed data blocks; CRC32 on completed data sf;
|
||||
//TODO: Embedded GPS Calculations
|
||||
//TODO: MBC full message CRC16 (does this include the header or not though?)
|
||||
//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
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void dmr_data_burst_handler(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t databurst)
|
||||
{
|
||||
|
||||
uint32_t i, j, k;
|
||||
uint32_t CRCExtracted = 0;
|
||||
uint32_t CRCComputed = 0;
|
||||
uint32_t CRCCorrect = 0;
|
||||
uint32_t IrrecoverableErrors = 0;
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t block = state->data_block_counter[slot];
|
||||
|
||||
//BPTC 196x96 Specific
|
||||
uint8_t BPTCDeInteleavedData[196];
|
||||
uint8_t BPTCDmrDataBit[96];
|
||||
uint8_t BPTCDmrDataByte[12];
|
||||
|
||||
//Embedded Signalling Specific
|
||||
uint8_t BptcDataMatrix[8][16];
|
||||
uint8_t LC_DataBit[77];
|
||||
uint8_t LC_DataBytes[10];
|
||||
int Burst = -1;
|
||||
|
||||
//Unified PDU (is this the best nomenclature) Bytes
|
||||
uint8_t DMR_PDU[25]; //using 25 bytes as the max for now
|
||||
uint8_t DMR_PDU_bits[196]; //bitwise version of unified payload, will probably be a lot easier to use this w/ manual
|
||||
memset (DMR_PDU, 0, sizeof (DMR_PDU));
|
||||
memset (DMR_PDU_bits, 0, sizeof (DMR_PDU_bits));
|
||||
|
||||
uint8_t R[3];
|
||||
uint8_t BPTCReservedBits = 0;
|
||||
|
||||
uint32_t crcmask = 0;
|
||||
uint8_t crclen = 0;
|
||||
|
||||
uint8_t is_bptc = 0;
|
||||
uint8_t is_trellis = 0;
|
||||
uint8_t is_emb = 0;
|
||||
uint8_t is_lc = 0;
|
||||
uint8_t is_full = 0;
|
||||
uint8_t pdu_len = 0;
|
||||
uint8_t pdu_start = 0; //starting value of pdu (0 normal, 2 for confirmed)
|
||||
|
||||
switch(databurst){
|
||||
case 0x00: //PI
|
||||
is_bptc = 1;
|
||||
crclen = 16;
|
||||
crcmask = 0x6969; //insert pi and 69 jokes here
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " PI ");
|
||||
break;
|
||||
case 0x01: //VLC
|
||||
is_bptc = 1;
|
||||
is_lc = 1;
|
||||
crclen = 24;
|
||||
crcmask = 0x969696;
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " VLC ");
|
||||
break;
|
||||
case 0x02: //TLC
|
||||
is_bptc = 1;
|
||||
is_lc = 1;
|
||||
crcmask = 0x999999;
|
||||
crclen = 24;
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " TLC ");
|
||||
break;
|
||||
case 0x03: //CSBK
|
||||
is_bptc = 1;
|
||||
crclen = 16;
|
||||
crcmask = 0xA5A5;
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " CSBK");
|
||||
break;
|
||||
case 0x04: //MBC Header
|
||||
is_bptc = 1;
|
||||
crclen = 16;
|
||||
crcmask = 0xAAAA;
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " MBCH");
|
||||
break;
|
||||
case 0x05: //MBC Continuation
|
||||
is_bptc = 1;
|
||||
//let block assembler carry out crc on the completed message
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " MBCC");
|
||||
break;
|
||||
case 0x06: //Data Header
|
||||
is_bptc = 1;
|
||||
crclen = 16;
|
||||
crcmask = 0xCCCC;
|
||||
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
|
||||
if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
pdu_len = 10;
|
||||
pdu_start = 2; //start at plus two when assembling
|
||||
}
|
||||
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
|
||||
if (state->data_conf_data[slot] == 1)
|
||||
{
|
||||
pdu_len = 16;
|
||||
pdu_start = 2; //start at plus two when assembling
|
||||
}
|
||||
sprintf(state->fsubtype, " R34D ");
|
||||
break;
|
||||
case 0x09: //Idle
|
||||
//pseudo-random data fill, no need to do anything with this
|
||||
sprintf(state->fsubtype, " IDLE ");
|
||||
break;
|
||||
case 0x0A: //1 Rate Data
|
||||
crclen = 9; //confirmed data only
|
||||
crcmask = 0x1FF;
|
||||
is_full = 1;
|
||||
pdu_len = 25; //196 bits - 24.5 bytes
|
||||
sprintf(state->fsubtype, " R_1D ");
|
||||
break;
|
||||
case 0x0B: //Unified Data
|
||||
is_bptc = 1;
|
||||
crclen = 16;
|
||||
crcmask = 0x3333;
|
||||
pdu_len = 12; //12 bytes
|
||||
sprintf(state->fsubtype, " UDAT ");
|
||||
break;
|
||||
//special types (not real data 'sync' bursts)
|
||||
case 0xEB: //Embedded Signalling
|
||||
is_emb = 1;
|
||||
pdu_len = 9;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (databurst != 0xEB)
|
||||
{
|
||||
if (state->dmr_ms_mode == 0) fprintf(stderr, "| Color Code=%02d ", state->dmr_color_code);
|
||||
fprintf(stderr, "|%s", state->fsubtype);
|
||||
}
|
||||
|
||||
//Most Data Sync Burst types will use the bptc 196x96
|
||||
if (is_bptc)
|
||||
{
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
IrrecoverableErrors = 0;
|
||||
|
||||
/* Deinterleave DMR data */
|
||||
BPTCDeInterleaveDMRData(info, BPTCDeInteleavedData);
|
||||
|
||||
/* Extract the BPTC 196,96 DMR data */
|
||||
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);
|
||||
|
||||
/* Convert the 96 bits BPTC data into 12 bytes */
|
||||
k = 0;
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
BPTCDmrDataByte[i] = 0;
|
||||
for(j = 0; j < 8; j++)
|
||||
{
|
||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] << 1;
|
||||
BPTCDmrDataByte[i] = BPTCDmrDataByte[i] | (BPTCDmrDataBit[k] & 0x01);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
|
||||
CRCExtracted = 0;
|
||||
for(i = 0; i < crclen; i++)
|
||||
{
|
||||
CRCExtracted = CRCExtracted << 1;
|
||||
CRCExtracted = CRCExtracted | (uint32_t)(BPTCDmrDataBit[i + 96 - crclen] & 1);
|
||||
}
|
||||
|
||||
/* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */
|
||||
CRCExtracted = CRCExtracted ^ crcmask;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
//run CRC on individual blocks according to type and validate each individual block
|
||||
}
|
||||
|
||||
//run CCITT on other data forms
|
||||
else //will still run on unconfirmed data (shouldn't matter other than a possible bogus warning message)
|
||||
{
|
||||
CRCComputed = ComputeCrcCCITT(BPTCDmrDataBit);
|
||||
if (CRCComputed == CRCExtracted) CRCCorrect = 1;
|
||||
else CRCCorrect = 0;
|
||||
}
|
||||
|
||||
if (databurst == 0x04 || databurst == 0x06) //MBC Header, Data Header
|
||||
{
|
||||
if (CRCCorrect)
|
||||
{
|
||||
state->data_block_crc_valid[slot][0] = 1;
|
||||
}
|
||||
else state->data_block_crc_valid[slot][0] = 0;
|
||||
}
|
||||
|
||||
/* Convert corrected x bytes into x*8 bits */
|
||||
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
|
||||
{
|
||||
BPTCDmrDataBit[j + 0] = (BPTCDmrDataByte[i+pdu_start] >> 7) & 0x01;
|
||||
BPTCDmrDataBit[j + 1] = (BPTCDmrDataByte[i+pdu_start] >> 6) & 0x01;
|
||||
BPTCDmrDataBit[j + 2] = (BPTCDmrDataByte[i+pdu_start] >> 5) & 0x01;
|
||||
BPTCDmrDataBit[j + 3] = (BPTCDmrDataByte[i+pdu_start] >> 4) & 0x01;
|
||||
BPTCDmrDataBit[j + 4] = (BPTCDmrDataByte[i+pdu_start] >> 3) & 0x01;
|
||||
BPTCDmrDataBit[j + 5] = (BPTCDmrDataByte[i+pdu_start] >> 2) & 0x01;
|
||||
BPTCDmrDataBit[j + 6] = (BPTCDmrDataByte[i+pdu_start] >> 1) & 0x01;
|
||||
BPTCDmrDataBit[j + 7] = (BPTCDmrDataByte[i+pdu_start] >> 0) & 0x01;
|
||||
}
|
||||
|
||||
//convert to unified DMR_PDU and DMR_PDU_bits
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
{
|
||||
DMR_PDU[i] = BPTCDmrDataByte[i+pdu_start];
|
||||
}
|
||||
|
||||
for (i = 0; i < pdu_len * 8; i++)
|
||||
{
|
||||
DMR_PDU_bits[i] = BPTCDmrDataBit[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Embedded Signalling will use BPTC 128x77
|
||||
if (is_emb)
|
||||
{
|
||||
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
IrrecoverableErrors = 0;
|
||||
|
||||
/* First step : Reconstitute the BPTC 16x8 matrix */
|
||||
Burst = 1; /* Burst B to E contains embedded signaling data */
|
||||
k = 0;
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
for(j = 0; j < 8; j++)
|
||||
{
|
||||
/* Only the LSBit of the byte is stored */
|
||||
BptcDataMatrix[j][i] = state->dmr_embedded_signalling[slot][Burst][k+8];
|
||||
k++;
|
||||
|
||||
/* Go on to the next burst once 32 bit
|
||||
* of the SNYC have been stored */
|
||||
if(k >= 32)
|
||||
{
|
||||
k = 0;
|
||||
Burst++;
|
||||
}
|
||||
} /* End for(j = 0; j < 8; j++) */
|
||||
} /* End for(i = 0; i < 16; i++) */
|
||||
|
||||
/* Extract the 72 LC bit (+ 5 CRC bit) of the matrix */
|
||||
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;
|
||||
|
||||
/* Compute the 5 bit CRC */
|
||||
CRCComputed = ComputeCrc5Bit(LC_DataBit);
|
||||
|
||||
if(CRCExtracted == CRCComputed) CRCCorrect = 1;
|
||||
else CRCCorrect = 0;
|
||||
|
||||
for (i = 0; i < 72; i++)
|
||||
{
|
||||
DMR_PDU_bits[i] = LC_DataBit[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&LC_DataBit[i*8], 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//the ugly one
|
||||
if (is_trellis)
|
||||
{
|
||||
CRCExtracted = 0;
|
||||
CRCComputed = 0;
|
||||
IrrecoverableErrors = 1; //can't be tested, but maybe can poll trellis decoder for a value in the future
|
||||
|
||||
uint8_t tdibits[98];
|
||||
memset (tdibits, 0, sizeof(tdibits));
|
||||
|
||||
//reconstitute info bits into reverse ordered dibits for the trellis decoder
|
||||
for (i = 0; i < 98; i++)
|
||||
{
|
||||
tdibits[97-i] = (info[i*2] << 1) | info[i*2+1];
|
||||
}
|
||||
|
||||
unsigned char TrellisReturn[18];
|
||||
memset (TrellisReturn, 0, sizeof(TrellisReturn));
|
||||
|
||||
CDMRTrellisDecode(tdibits, TrellisReturn);
|
||||
|
||||
for (i = 0; i < pdu_len; i++) //18
|
||||
{
|
||||
DMR_PDU[i] = (uint8_t)TrellisReturn[i+pdu_start];
|
||||
}
|
||||
|
||||
for(i = 0, j = 0; i < pdu_len; i++, j+=8)
|
||||
{
|
||||
DMR_PDU_bits[j + 0] = (TrellisReturn[i+pdu_start] >> 7) & 0x01;
|
||||
DMR_PDU_bits[j + 1] = (TrellisReturn[i+pdu_start] >> 6) & 0x01;
|
||||
DMR_PDU_bits[j + 2] = (TrellisReturn[i+pdu_start] >> 5) & 0x01;
|
||||
DMR_PDU_bits[j + 3] = (TrellisReturn[i+pdu_start] >> 4) & 0x01;
|
||||
DMR_PDU_bits[j + 4] = (TrellisReturn[i+pdu_start] >> 3) & 0x01;
|
||||
DMR_PDU_bits[j + 5] = (TrellisReturn[i+pdu_start] >> 2) & 0x01;
|
||||
DMR_PDU_bits[j + 6] = (TrellisReturn[i+pdu_start] >> 1) & 0x01;
|
||||
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
|
||||
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
DMR_PDU[i] = (uint8_t)ConvertBitIntoBytes(&info[i*8], 8);
|
||||
}
|
||||
//leftover 4 bits, manual doesn't say which 4 so assuming last 4
|
||||
//pushing last 4 to 25 and shifting it
|
||||
DMR_PDU[25] = (uint8_t)ConvertBitIntoBytes(&info[192], 4);
|
||||
DMR_PDU[25] = DMR_PDU[25] << 4;
|
||||
|
||||
//copy info to dmr_pdu_bits
|
||||
memcpy(DMR_PDU_bits, info, sizeof(DMR_PDU_bits));
|
||||
|
||||
}
|
||||
|
||||
|
||||
//time for some pi
|
||||
if (databurst == 0x00) dmr_pi (opts, state, DMR_PDU, CRCCorrect, IrrecoverableErrors);
|
||||
|
||||
//full link control
|
||||
if (databurst == 0x01) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 1); //VLC
|
||||
if (databurst == 0x02) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 2); //TLC
|
||||
if (databurst == 0xEB) dmr_flco (opts, state, DMR_PDU_bits, CRCCorrect, IrrecoverableErrors, 3); //EMB
|
||||
|
||||
//dmr data header and multi block types (header, 1/2, 3/4, 1, Unified) - type 1
|
||||
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
|
||||
|
||||
//is unified data handled like normal data, or control signalling data?
|
||||
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)
|
||||
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
|
||||
if (databurst == 0x04)
|
||||
{
|
||||
state->data_block_counter[slot] = 0; //zero block counter before running header
|
||||
dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
|
||||
}
|
||||
if (databurst == 0x05) dmr_block_assembler (opts, state, DMR_PDU, pdu_len, databurst, 2);
|
||||
|
||||
//print the unified PDU format here, if not slot idle
|
||||
if (opts->payload == 1 && databurst != 0x09)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " DMR PDU Payload ");
|
||||
for (i = 0; i < pdu_len; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", DMR_PDU[i]);
|
||||
}
|
||||
|
||||
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, ".");
|
||||
// }
|
||||
|
||||
fprintf (stderr,"%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
587
src/dmr_flco.c
Normal file
587
src/dmr_flco.c
Normal file
@@ -0,0 +1,587 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_flco.c
|
||||
* DMR Full Link Control, Short Link Control, TACT/CACH and related funtions
|
||||
*
|
||||
* Portions of link control/voice burst/vlc/tlc from LouisErigHerve
|
||||
* Source: https://github.com/LouisErigHerve/dsd/blob/master/src/dmr_sync.c
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
||||
{
|
||||
|
||||
//force slot to 0 if using dmr mono handling
|
||||
if (opts->dmr_mono == 1) state->currentslot = 0;
|
||||
|
||||
uint8_t pf = 0;
|
||||
uint8_t reserved = 0;
|
||||
uint8_t flco = 0;
|
||||
uint8_t fid = 0;
|
||||
uint8_t so = 0;
|
||||
uint32_t target = 0;
|
||||
uint32_t source = 0;
|
||||
int restchannel = -1;
|
||||
int is_cap_plus = 0;
|
||||
int is_alias = 0;
|
||||
int is_gps = 0;
|
||||
|
||||
|
||||
pf = (uint8_t)(lc_bits[0]); //Protect Flag
|
||||
reserved = (uint8_t)(lc_bits[1]); //Reserved
|
||||
flco = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //Full Link Control Opcode
|
||||
fid = (uint8_t)ConvertBitIntoBytes(&lc_bits[8], 8); //Feature set ID (FID)
|
||||
so = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 8); //Service Options
|
||||
target = (uint32_t)ConvertBitIntoBytes(&lc_bits[24], 24); //Target or Talk Group
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
||||
|
||||
//look for Cap+ on VLC header, then set source and/or rest channel appropriately
|
||||
if (type == 1 && fid == 0x10 && flco == 0x04)
|
||||
{
|
||||
is_cap_plus = 1;
|
||||
restchannel = (int)ConvertBitIntoBytes(&lc_bits[48], 8);
|
||||
source = (uint32_t)ConvertBitIntoBytes(&lc_bits[56], 16);
|
||||
}
|
||||
|
||||
//Embedded Talker Alias Header Only (format and len storage)
|
||||
if (IrrecoverableErrors == 0)
|
||||
{
|
||||
if (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)
|
||||
{
|
||||
is_alias = 1;
|
||||
dmr_embedded_alias_blocks(opts, state, lc_bits);
|
||||
}
|
||||
|
||||
//Embedded GPS
|
||||
if (type == 3 && flco == 0x08)
|
||||
{
|
||||
is_gps = 1;
|
||||
dmr_embedded_gps(opts, state, lc_bits);
|
||||
}
|
||||
}
|
||||
|
||||
//will want to continue to observe for different flco and fid combinations to find out their meaning
|
||||
//Standard Addressing/Cap+ Addressing (trying to avoid embedded alias and gps, etc)
|
||||
if(IrrecoverableErrors == 0 && is_alias == 0 && is_gps == 0)
|
||||
{
|
||||
//set overarching manufacturer in use when non-standard feature id set is up
|
||||
//may not want to set moto 0x10 here either, lots of radios use that set as well
|
||||
if (fid != 0) state->dmr_mfid = fid;
|
||||
|
||||
if (type != 2) //VLC and EMB, set our target, source, so, and fid per channel
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dmr_fid = fid;
|
||||
state->dmr_so = so;
|
||||
state->lasttg = target;
|
||||
state->lastsrc = source;
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmr_fidR = fid;
|
||||
state->dmr_soR = so;
|
||||
state->lasttgR = target;
|
||||
state->lastsrcR = source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (type == 2) //TLC, zero out target, source, so, and fid per channel, and other odd and ends
|
||||
{
|
||||
//I wonder which of these we truly want to zero out, possibly none of them
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
// state->dmr_fid = 0;
|
||||
// state->dmr_so = 0;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->payload_mi = 0;
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
// state->dmr_fidR = 0;
|
||||
// state->dmr_soR = 0;
|
||||
state->lasttgR = 0;
|
||||
state->lastsrcR = 0;
|
||||
state->payload_miR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (restchannel != state->dmr_rest_channel && restchannel != -1)
|
||||
{
|
||||
state->dmr_rest_channel = restchannel;
|
||||
}
|
||||
|
||||
if (type == 1) fprintf (stderr, "%s \n", KGRN);
|
||||
if (type == 2) fprintf (stderr, "%s \n", KRED);
|
||||
if (type == 3) fprintf (stderr, "%s", KGRN);
|
||||
|
||||
fprintf (stderr, " SLOT %d ", state->currentslot+1);
|
||||
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) fprintf (stderr, "Private "); //UU_V_Ch_Usr
|
||||
else fprintf (stderr, "Group "); //Grp_V_Ch_Usr
|
||||
|
||||
if(so & 0x80) fprintf(stderr, "Emergency ");
|
||||
if(so & 0x40)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, "Encrypted ");
|
||||
}
|
||||
|
||||
/* Check the "Service Option" bits */
|
||||
if(so & 0x30)
|
||||
{
|
||||
/* Experimentally determined with DSD+,
|
||||
* is equal to 0x2, this is a TXI call */
|
||||
if((so & 0x30) == 0x20) fprintf(stderr, "TXI ");
|
||||
else fprintf(stderr, "Reserved=%d ", (so & 0x30) >> 4);
|
||||
}
|
||||
if(so & 0x08) fprintf(stderr, "Broadcast ");
|
||||
if(so & 0x04) fprintf(stderr, "OVCM ");
|
||||
if(so & 0x03)
|
||||
{
|
||||
if((so & 0x03) == 0x01) fprintf(stderr, "Priority 1 ");
|
||||
else if((so & 0x03) == 0x02) fprintf(stderr, "Priority 2 ");
|
||||
else if((so & 0x03) == 0x03) fprintf(stderr, "Priority 3 ");
|
||||
else fprintf(stderr, "No Priority "); /* We should never go here */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (restchannel != -1)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "Cap+ R-Ch %d", restchannel);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
|
||||
//group labels
|
||||
for (int i = 0; i < state->group_tally; i++)
|
||||
{
|
||||
//ROMAN! Change target to source if you prefer
|
||||
if (state->group_array[i].groupNumber == target)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, "[%s] ", state->group_array[i].groupName);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->K != 0 && fid == 0x10 && so & 0x40)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "Key %lld ", state->K);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (state->K1 != 0 && fid == 0x68 && so & 0x40)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Key %010llX ", state->K1);
|
||||
if (state->K2 != 0) fprintf (stderr, "%016llX ", state->K2);
|
||||
if (state->K4 != 0) fprintf (stderr, "%016llX %016llX", state->K3, state->K4);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//externalized dmr cach - tact and slco fragment handling
|
||||
uint8_t dmr_cach (dsd_opts * opts, dsd_state * state, uint8_t cach_bits[25])
|
||||
{
|
||||
int i, j;
|
||||
uint8_t err = 0;
|
||||
uint8_t tact_valid = 0;
|
||||
uint8_t cach_valid = 0;
|
||||
|
||||
bool h1, h2, h3, crc;
|
||||
|
||||
//dump payload - testing
|
||||
uint8_t slco_raw_bits[68]; //raw
|
||||
uint8_t slco_bits[68]; //de-interleaved
|
||||
|
||||
//tact pdu
|
||||
uint8_t tact_bits[7];
|
||||
uint8_t at = 0; //access type, set to 1 during continuous transmission mode
|
||||
uint8_t slot = 2; //tdma time slot
|
||||
uint8_t lcss = 0; //link control start stop (9.3.3) NOTE: There is no Single fragment LC defined for CACH signalling
|
||||
|
||||
//cach_bits are already de-interleaved upon initial collection (still needs secodary slco de-interleave)
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
tact_bits[i] = cach_bits[i];
|
||||
}
|
||||
|
||||
//run hamming 7_4 on the tact_bits (redundant, since we do it earlier, but need the lcss)
|
||||
if ( Hamming_7_4_decode (tact_bits) )
|
||||
{
|
||||
at = tact_bits[0]; //any useful tricks with this? csbk on/off etc?
|
||||
slot = tact_bits[1]; //
|
||||
lcss = (tact_bits[2] << 1) | tact_bits[3];
|
||||
tact_valid = 1; //set to 1 for valid, else remains 0.
|
||||
//fprintf (stderr, "AT=%d LCSS=%d - ", at, lcss); //debug print
|
||||
}
|
||||
else //probably skip/memset/zeroes with else statement?
|
||||
{
|
||||
//do something?
|
||||
err = 1;
|
||||
//return (err);
|
||||
}
|
||||
|
||||
//determine counter value based on lcss value
|
||||
if (lcss == 0) //run as single block/fragment NOTE: There is no Single fragment LC defined for CACH signalling (but is mentioned in the manual table)
|
||||
{
|
||||
//reset the full cach, even if we aren't going to use it, may be beneficial for next time
|
||||
state->dmr_cach_counter = 0; //first fragment, set to zero.
|
||||
memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment));
|
||||
|
||||
//seperate
|
||||
for (i = 0; i < 17; i++)
|
||||
{
|
||||
slco_raw_bits[i] = cach_bits[i+7];
|
||||
}
|
||||
|
||||
//De-interleave
|
||||
int src = 0;
|
||||
for (i = 0; i < 17; i++)
|
||||
{
|
||||
src = (i * 4) % 67;
|
||||
slco_bits[i] = slco_raw_bits[src];
|
||||
}
|
||||
//slco_bits[i] = slco_raw_bits[i];
|
||||
|
||||
//hamming check here
|
||||
h1 = Hamming17123 (slco_bits + 0);
|
||||
|
||||
//run single - manual would suggest that though this exists, there is no support? or perhaps its manufacturer only thing?
|
||||
if (h1) dmr_slco (opts, state, slco_bits);
|
||||
else
|
||||
{
|
||||
err = 1;
|
||||
//return (err);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
if (lcss == 1) //first block, reset counters and memset
|
||||
{
|
||||
//reset the full cach and counter
|
||||
state->dmr_cach_counter = 0;
|
||||
memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment));
|
||||
}
|
||||
if (lcss == 3) state->dmr_cach_counter++; //continuation, so increment counter by one.
|
||||
if (lcss == 2) //final segment - assemble, de-interleave, hamming, crc, and execute
|
||||
{
|
||||
state->dmr_cach_counter = 3;
|
||||
}
|
||||
|
||||
//sanity check
|
||||
if (state->dmr_cach_counter > 3) //marginal/shaky/bad signal or tuned away
|
||||
{
|
||||
//zero out complete fragment array
|
||||
lcss = 5; //toss away value
|
||||
state->dmr_cach_counter = 0;
|
||||
memset (state->dmr_cach_fragment, 0, sizeof (state->dmr_cach_fragment));
|
||||
err = 1;
|
||||
return (err);
|
||||
}
|
||||
|
||||
//add fragment to array
|
||||
for (i = 0; i < 17; i++)
|
||||
{
|
||||
state->dmr_cach_fragment[state->dmr_cach_counter][i] = cach_bits[i+7];
|
||||
}
|
||||
|
||||
if (lcss == 2) //last block arrived, compile, hamming, crc and send off to dmr_slco
|
||||
{
|
||||
//assemble
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
for (i = 0; i < 17; i++)
|
||||
{
|
||||
slco_raw_bits[i+(17*j)] = state->dmr_cach_fragment[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
//De-interleave method, hamming, and crc from Boatbod OP25
|
||||
|
||||
//De-interleave
|
||||
int src = 0;
|
||||
for (i = 0; i < 67; i++)
|
||||
{
|
||||
src = (i * 4) % 67;
|
||||
slco_bits[i] = slco_raw_bits[src];
|
||||
}
|
||||
slco_bits[i] = slco_raw_bits[i];
|
||||
|
||||
//hamming checks here
|
||||
h1 = Hamming17123 (slco_bits + 0);
|
||||
h2 = Hamming17123 (slco_bits + 17);
|
||||
h3 = Hamming17123 (slco_bits + 34);
|
||||
|
||||
// remove hamming and leave 36 bits of Short LC
|
||||
for (i = 17; i < 29; i++) {
|
||||
slco_bits[i-5] = slco_bits[i];
|
||||
}
|
||||
for (i = 34; i < 46; i++) {
|
||||
slco_bits[i-10] = slco_bits[i];
|
||||
}
|
||||
|
||||
//zero out the hangover bits
|
||||
for (i = 36; i < 68; i++)
|
||||
{
|
||||
slco_bits[i] = 0;
|
||||
}
|
||||
|
||||
//run crc8
|
||||
crc = crc8_ok(slco_bits, 36);
|
||||
|
||||
//only run SLCO on good everything
|
||||
if (h1 && h2 && h3 && crc) dmr_slco (opts, state, slco_bits);
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, " SLCO CRC ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
}
|
||||
return (err); //return err value based on success or failure, even if we aren't checking it
|
||||
}
|
||||
|
||||
void dmr_slco (dsd_opts * opts, dsd_state * state, uint8_t slco_bits[])
|
||||
{
|
||||
int i;
|
||||
uint8_t slco_bytes[6]; //completed byte blocks for payload print
|
||||
for (i = 0; i < 5; i++) slco_bytes[i] = (uint8_t)ConvertBitIntoBytes(&slco_bits[i*8], 8);
|
||||
slco_bytes[5] = (uint8_t)ConvertBitIntoBytes(&slco_bits[32], 4);
|
||||
|
||||
|
||||
//just going to decode the Short LC with all potential parameters known
|
||||
uint8_t slco = (uint8_t)ConvertBitIntoBytes(&slco_bits[0], 4);
|
||||
uint8_t model = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 2);
|
||||
uint16_t netsite = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 12);
|
||||
uint8_t reg = slco_bits[18]; //registration required/not required or normalchanneltype/composite cch
|
||||
uint8_t csc = (uint16_t)ConvertBitIntoBytes(&slco_bits[19], 9); //common slot counter, 0-511
|
||||
uint16_t net = 0;
|
||||
uint16_t site = 0;
|
||||
char model_str[8];
|
||||
sprintf (model_str, "%s", "");
|
||||
//activity update stuff
|
||||
uint8_t ts1_act = (uint8_t)ConvertBitIntoBytes(&slco_bits[4], 4); //activity update ts1
|
||||
uint8_t ts2_act = (uint8_t)ConvertBitIntoBytes(&slco_bits[8], 4); //activity update ts2
|
||||
uint8_t ts1_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[12], 8); //ts1 address hash (crc8) //361-1 B.3.7
|
||||
uint8_t ts2_hash = (uint8_t)ConvertBitIntoBytes(&slco_bits[20], 8); //ts2 address hash (crc8) //361-1 B.3.7
|
||||
|
||||
//Sys_Parms
|
||||
if (slco == 0x2 || slco == 0x3)
|
||||
{
|
||||
if (model == 0) //Tiny
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 9);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&slco_bits[15], 3);
|
||||
sprintf (model_str, "%s", "Tiny");
|
||||
}
|
||||
else if (model == 1) //Small
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 7);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&slco_bits[13], 5);
|
||||
sprintf (model_str, "%s", "Small");
|
||||
}
|
||||
else if (model == 2) //Large
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 4);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&slco_bits[10], 8);
|
||||
sprintf (model_str, "%s", "Large");
|
||||
}
|
||||
else if (model == 3) //Huge
|
||||
{
|
||||
net = (uint16_t)ConvertBitIntoBytes(&slco_bits[6], 2);
|
||||
site = (uint16_t)ConvertBitIntoBytes(&slco_bits[8], 10);
|
||||
sprintf (model_str, "%s", "Huge");
|
||||
}
|
||||
}
|
||||
|
||||
//Con+
|
||||
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);
|
||||
|
||||
//initial line break
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
|
||||
if (slco == 0x2) //C_SYS_Parms
|
||||
fprintf (stderr, " C_SYS_PARMS - %s - Net ID: %d Site ID: %d - Reg Req: %d - CSC: %d ", model_str, net, site, reg, csc);
|
||||
else if (slco == 0x3) //P_SYS_Parms
|
||||
fprintf (stderr, " P_SYS_PARMS - %s - Net ID: %d Site ID: %d - Comp Ch: %d ", model_str, net, site, reg);
|
||||
else if (slco == 0x0) //null
|
||||
fprintf (stderr, " SLCO NULL ");
|
||||
else if (slco == 0x1)
|
||||
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_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Voice Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
}
|
||||
|
||||
else if (slco == 0xA)
|
||||
{
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding_sub, "%s", "Con+ ");
|
||||
fprintf (stderr, " SLCO Connect Plus Control Channel - Net ID: %d Site ID: %d", con_netid, con_siteid);
|
||||
}
|
||||
|
||||
else if (slco == 0xF)
|
||||
{
|
||||
state->dmr_mfid = 0x10;
|
||||
sprintf (state->dmr_branding_sub, "%s", "Cap+ ");
|
||||
fprintf (stderr, " SLCO Capacity Plus Rest Channel %d", restchannel);
|
||||
}
|
||||
|
||||
else fprintf (stderr, " SLCO Unknown - %d ", slco);
|
||||
|
||||
if (opts->payload == 1 && slco != 0) //if not SLCO NULL
|
||||
{
|
||||
fprintf (stderr, "\n SLCO Completed Block ");
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
fprintf (stderr, "[%02X]", slco_bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
//externalize embedded alias to keep the flco function relatively clean
|
||||
void dmr_embedded_alias_header (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
{
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t pf;
|
||||
uint8_t res;
|
||||
uint8_t format = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 2);
|
||||
uint8_t len;
|
||||
|
||||
//this len seems to pertain to number of blocks? not bit len.
|
||||
//len = (uint8_t)ConvertBitIntoBytes(&lc_bits[18], 5);
|
||||
|
||||
if (format == 0) len = 7;
|
||||
else if (format == 1 || format == 2) len = 8;
|
||||
else len = 16;
|
||||
|
||||
state->dmr_alias_format[slot] = format;
|
||||
state->dmr_alias_len[slot] = len;
|
||||
|
||||
//fprintf (stderr, "F: %d L: %d - ", format, len);
|
||||
|
||||
}
|
||||
|
||||
void dmr_embedded_alias_blocks (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Embedded Alias: ");
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t block = (uint8_t)ConvertBitIntoBytes(&lc_bits[2], 6); //FLCO equals block number
|
||||
uint8_t format = state->dmr_alias_format[slot]; //0=7-bit; 1=ISO8; 2=UTF-8; 3=UTF16BE
|
||||
uint8_t len = state->dmr_alias_len[slot];
|
||||
uint8_t start; //starting position depends on context of block and format
|
||||
|
||||
//there is some issue with the next three lines of code that prevent proper assignments, not sure what.
|
||||
//if (block > 4) start = 16;
|
||||
//else if (block == 4 && format > 0) start = 23; //8-bit and 16-bit chars
|
||||
//else start = 24;
|
||||
|
||||
//forcing start to 16 make it work on 8-bit alias, len seems okay when set off of format
|
||||
start = 16;
|
||||
len = 8;
|
||||
|
||||
// fprintf (stderr, "block: %d start: %d len: %d ", block, start, len);
|
||||
|
||||
//all may not be used depending on format, len, start.
|
||||
uint16_t A0, A1, A2, A3, A4, A5, A6;
|
||||
|
||||
//sanity check
|
||||
if (block > 7) block = 4; //prevent oob array (although we should never get here)
|
||||
|
||||
if (len > 6) //if not greater than zero, then the header hasn't arrived yet
|
||||
{
|
||||
A0 = 0; A1 = 0; A2 = 0; A3 = 0; A4 = 0; A5 = 0; A6 = 0; //NULL ASCII Characters
|
||||
A0 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*0], len);
|
||||
A1 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*1], len);
|
||||
A2 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*2], len);
|
||||
A3 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*3], len);
|
||||
A4 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*4], len);
|
||||
A5 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*5], len);
|
||||
A6 = (uint16_t)ConvertBitIntoBytes(&lc_bits[start+len*6], len);
|
||||
|
||||
//just going to assign the usual ascii set here to prevent 'naughty' characters, sans diacriticals
|
||||
if (A0 > 0x19 && A0 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][0], "%c", A0);
|
||||
if (A1 > 0x19 && A1 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][1], "%c", A1);
|
||||
if (A2 > 0x19 && A2 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][2], "%c", A2);
|
||||
if (A3 > 0x19 && A3 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][3], "%c", A3);
|
||||
if (A4 > 0x19 && A4 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][4], "%c", A4);
|
||||
if (A5 > 0x19 && A5 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][5], "%c", A5);
|
||||
if (A6 > 0x19 && A6 < 0x7F) sprintf (state->dmr_alias_block_segment[slot][block-4][6], "%c", A6);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 7; j++)
|
||||
{
|
||||
fprintf (stderr, "%s", state->dmr_alias_block_segment[slot][i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else fprintf (stderr, "Missing Header Block Format and Len Data");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
}
|
||||
|
||||
//externalize embedded GPS
|
||||
void dmr_embedded_gps (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[])
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, " Embedded GPS");
|
||||
uint8_t pf = lc_bits[0];
|
||||
uint8_t res_a = lc_bits[1];
|
||||
uint8_t res_b = (uint8_t)ConvertBitIntoBytes(&lc_bits[16], 4);
|
||||
uint8_t pos_err = (uint8_t)ConvertBitIntoBytes(&lc_bits[20], 3);
|
||||
uint32_t lon = (uint32_t)ConvertBitIntoBytes(&lc_bits[23], 25);
|
||||
uint32_t lat = (uint32_t)ConvertBitIntoBytes(&lc_bits[48], 24);
|
||||
|
||||
//run calculations and print
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
139
src/dmr_le.c
Normal file
139
src/dmr_le.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_le.c
|
||||
* DMR Late Entry MI Fragment Assembly, Procesing, and related Alg functions
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//gather ambe_fr mi fragments for processing
|
||||
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])
|
||||
{
|
||||
|
||||
uint8_t slot = state->currentslot;
|
||||
|
||||
//collect our fragments and place them into storage
|
||||
state->late_entry_mi_fragment[slot][vc][0] = (uint64_t)ConvertBitIntoBytes(&ambe_fr[3][0], 4);
|
||||
state->late_entry_mi_fragment[slot][vc][1] = (uint64_t)ConvertBitIntoBytes(&ambe_fr2[3][0], 4);
|
||||
state->late_entry_mi_fragment[slot][vc][2] = (uint64_t)ConvertBitIntoBytes(&ambe_fr3[3][0], 4);
|
||||
|
||||
if (vc == 6) dmr_late_entry_mi (opts, state);
|
||||
|
||||
}
|
||||
|
||||
void dmr_late_entry_mi (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
uint8_t slot = state->currentslot;
|
||||
int i, j;
|
||||
int g[3];
|
||||
unsigned char mi_go_bits[24];
|
||||
|
||||
uint64_t mi_test = 0;
|
||||
uint64_t go_test = 0;
|
||||
uint64_t mi_corrected = 0;
|
||||
uint64_t go_corrected = 0;
|
||||
|
||||
mi_test = (state->late_entry_mi_fragment[slot][1][0] << 32L) | (state->late_entry_mi_fragment[slot][2][0] << 28) | (state->late_entry_mi_fragment[slot][3][0] << 24) |
|
||||
(state->late_entry_mi_fragment[slot][1][1] << 20) | (state->late_entry_mi_fragment[slot][2][1] << 16) | (state->late_entry_mi_fragment[slot][3][1] << 12) |
|
||||
(state->late_entry_mi_fragment[slot][1][2] << 8) | (state->late_entry_mi_fragment[slot][2][2] << 4) | (state->late_entry_mi_fragment[slot][3][2] << 0);
|
||||
|
||||
go_test = (state->late_entry_mi_fragment[slot][4][0] << 32L) | (state->late_entry_mi_fragment[slot][5][0] << 28) | (state->late_entry_mi_fragment[slot][6][0] << 24) |
|
||||
(state->late_entry_mi_fragment[slot][4][1] << 20) | (state->late_entry_mi_fragment[slot][5][1] << 16) | (state->late_entry_mi_fragment[slot][6][1] << 12) |
|
||||
(state->late_entry_mi_fragment[slot][4][2] << 8) | (state->late_entry_mi_fragment[slot][5][2] << 4) | (state->late_entry_mi_fragment[slot][6][2] << 0);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
mi_go_bits[i] = (( mi_test << (i+j*12) ) & 0x800000000) >> 35;
|
||||
mi_go_bits[i+12] = (( go_test << (i+j*12) ) & 0x800000000) >> 35;
|
||||
}
|
||||
//execute golay decode and assign pass or fail to g
|
||||
if ( Golay_24_12_decode(mi_go_bits) ) g[j] = 1;
|
||||
else g[j] = 0;
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
mi_corrected = mi_corrected << 1;
|
||||
mi_corrected |= mi_go_bits[i];
|
||||
go_corrected = go_corrected << 1;
|
||||
go_corrected |= mi_go_bits[i+12];
|
||||
}
|
||||
}
|
||||
|
||||
int mi_final = 0;
|
||||
mi_final = (mi_corrected >> 4) & 0xFFFFFFFF;
|
||||
|
||||
if (g[0] && g[1] && g[2])
|
||||
{
|
||||
if (slot == 0 && state->payload_algid != 0)
|
||||
{
|
||||
if (state->payload_mi != mi_final)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 1 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_mi, mi_final);
|
||||
state->payload_mi = mi_final;
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
if (slot == 1 && state->payload_algidR != 0)
|
||||
{
|
||||
if (state->payload_miR != mi_final)
|
||||
{
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf (stderr, " Slot 2 PI/LFSR and Late Entry MI Mismatch - %08X : %08X \n", state->payload_miR, mi_final);
|
||||
state->payload_miR = mi_final;
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dmr_alg_refresh (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dropL = 256;
|
||||
|
||||
if (state->K1 != 0)
|
||||
{
|
||||
state->DMRvcL = 0;
|
||||
}
|
||||
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
LFSR (state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dropR = 256;
|
||||
|
||||
if (state->K1 != 0)
|
||||
{
|
||||
state->DMRvcR = 0;
|
||||
}
|
||||
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
LFSR (state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dmr_alg_reset (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->dropL = 256;
|
||||
state->dropR = 256;
|
||||
state->DMRvcL = 0;
|
||||
state->DMRvcR = 0;
|
||||
state->payload_miP = 0;
|
||||
}
|
||||
|
||||
711
src/dmr_ms.c
711
src/dmr_ms.c
@@ -1,40 +1,58 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_ms.c
|
||||
* DMR MS/Simplex/Direct Mode Voice Handling and Data Gathering Routines
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
|
||||
//A subroutine for processing MS voice
|
||||
void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//fprintf (stderr, "\n Quick DMR Voice Testing\n");
|
||||
|
||||
int i, j, k, l, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
char ambe_fr4[4][24] = {0};
|
||||
char t_ambe_fr[4][24] = {9};
|
||||
char t_ambe_fr2[4][24] = {9};
|
||||
char t_ambe_fr3[4][24] = {9};
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
char ambe_fr4[4][24];
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
char m2[4][24];
|
||||
char m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
//standalone inbound rc sync exists on dibits 48-96?
|
||||
//or 44-92? of each potential payload, middle 10 ms or 30 ms frame
|
||||
char rcsync[25];
|
||||
char rcsyncdata[96]; //96 bit RC sync data
|
||||
char cachdata[13] = {0};
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
char cc[4];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
unsigned char EmbeddedSignallingInverse[16];
|
||||
int EmbeddedSignallingOk;
|
||||
unsigned int internalcolorcode;
|
||||
int internalslot;
|
||||
int activeslot;
|
||||
char redundancyA[36];
|
||||
char redundancyB[36];
|
||||
unsigned short int vc1;
|
||||
unsigned short int vc2;
|
||||
char EmbeddedSignalling[16];
|
||||
|
||||
//cach
|
||||
char cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
|
||||
//cach tact bits
|
||||
uint8_t tact_bits[7];
|
||||
|
||||
uint8_t emb_ok = 0;
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
uint8_t EmbeddedSignallingOk = 0;
|
||||
|
||||
uint8_t internalslot;
|
||||
uint8_t vc;
|
||||
|
||||
//dummy bits to pass to dburst for link control
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof (dummy_bits));
|
||||
|
||||
//add time to mirror printFrameSync
|
||||
time_t now;
|
||||
@@ -53,39 +71,43 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
return curr;
|
||||
}
|
||||
|
||||
//Init the color code status
|
||||
state->color_code_ok = 0;
|
||||
vc = 2;
|
||||
|
||||
vc1 = 2;
|
||||
vc2 = 2;
|
||||
|
||||
short int loop = 1;
|
||||
short int skipcount = 0;
|
||||
|
||||
//Hardset variables for MS
|
||||
//Hardset variables for MS/Mono
|
||||
state->currentslot = 0; //0
|
||||
internalslot = 0;
|
||||
activeslot = 0;
|
||||
|
||||
//Run Loop while the getting is good
|
||||
while (loop == 1) {
|
||||
//Note: Manual dibit inversion required here since I didn't seperate inverted return from normal return in framesync,
|
||||
//so getDibit doesn't know to invert it before it gets here
|
||||
|
||||
short int m = 0;
|
||||
|
||||
state->dmrburstL = 16; //Use 16 for Voice
|
||||
for (j = 0; j < 6; j++) {
|
||||
state->dmrburstL = 16;
|
||||
|
||||
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);
|
||||
|
||||
cachdata[i] = dibit;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
|
||||
tact_okay = 0;
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1)
|
||||
{
|
||||
//do nothing since we aren't loop locked forever.
|
||||
}
|
||||
|
||||
//internalslot = tact_bits[1];
|
||||
internalslot = 0;
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
@@ -97,12 +119,10 @@ 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);
|
||||
|
||||
state->dmr_stereo_payload[i+12] = dibit;
|
||||
redundancyA[i] = dibit;
|
||||
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -113,20 +133,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//check for repetitive data if caught in a 'no carrier' loop? Just picking random values.
|
||||
//this will test for no carrier (input signal) and return us to no sync state if necessary
|
||||
if (redundancyA[16] == redundancyB[16] && redundancyA[27] == redundancyB[27] &&
|
||||
redundancyA[01] == redundancyB[01] && redundancyA[32] == redundancyB[32] &&
|
||||
redundancyA[03] == redundancyB[03] && redundancyA[33] == redundancyB[33] &&
|
||||
redundancyA[13] == redundancyB[13] && redundancyA[07] == redundancyB[07] )
|
||||
{
|
||||
//goto END;
|
||||
}
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
redundancyB[i] = redundancyA[i];
|
||||
}
|
||||
|
||||
//Setup for Second AMBE Frame
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
@@ -138,10 +144,8 @@ 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);
|
||||
|
||||
state->dmr_stereo_payload[i+48] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -157,85 +161,37 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
|
||||
state->dmr_stereo_payload[i+66] = dibit;
|
||||
|
||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
|
||||
if (i < 4 || i > 19) //
|
||||
// load the superframe to do embedded signal processing
|
||||
if(vc > 1 && vc < 6) //grab on vc1 values 2-5 B C D and E
|
||||
{
|
||||
EmbeddedSignalling[2*i] = (1 & (dibit >> 1)); // bit 1
|
||||
EmbeddedSignalling[2*i+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
// load the superframe to do the voiceburstsync processing
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 6) //grab on vc1 values 2-5 B C D and E
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => SYNC data */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[vc1-1].Sync[i*2+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
if(internalslot == 1 && vc2 > 1 && vc2 < 6) //grab on vc2 values 2-5 B C D and E
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => SYNC data */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[vc2-1].Sync[i*2+1] = (1 & dibit); // bit 0
|
||||
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 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sync[24] = 0;
|
||||
EmbeddedSignallingOk = -1;
|
||||
|
||||
// for (i = 0; i < 16; i++)
|
||||
// {
|
||||
// EmbeddedSignallingInverse[i] = EmbeddedSignalling[i] ^ 1;
|
||||
// }
|
||||
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling))
|
||||
{
|
||||
EmbeddedSignallingOk = 1;
|
||||
}
|
||||
|
||||
//test for inverted signal - this should move to data, and have a slottype check here perhaps?
|
||||
// else if (QR_16_7_6_decode(EmbeddedSignallingInverse))
|
||||
// {
|
||||
// if (opts->inverted_dmr == 0)
|
||||
// {
|
||||
// opts->inverted_dmr = 1;
|
||||
// }
|
||||
// else opts->inverted_dmr = 0;
|
||||
// goto END;
|
||||
// }
|
||||
|
||||
internalcolorcode = 69; //set so we know if this value is being set properly
|
||||
if(EmbeddedSignallingOk == 1)
|
||||
{
|
||||
state->color_code = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
internalcolorcode = (unsigned int)((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
state->color_code_ok = EmbeddedSignallingOk;
|
||||
//Power Indicator, not the other PI (header)
|
||||
state->PI = (unsigned int)EmbeddedSignalling[4];
|
||||
state->PI_ok = EmbeddedSignallingOk;
|
||||
//Link Control Start Stop Indicator
|
||||
state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
state->LCSS_ok = EmbeddedSignallingOk;
|
||||
|
||||
}
|
||||
//else skipcount++;
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -245,12 +201,6 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
y++;
|
||||
z++;
|
||||
|
||||
//WIP for RC inbound sync data, part 2, second 24 bits (12 dibits)
|
||||
if (i <= 12)
|
||||
{
|
||||
rcsyncdata[i+12] = (dibit | 1) + 48; //test and double check positions for this sync data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Setup for Third AMBE Frame
|
||||
@@ -264,10 +214,8 @@ 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);
|
||||
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
@@ -277,229 +225,64 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
y++;
|
||||
z++;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ( ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) && opts->inverted_dmr == 0) ||
|
||||
((strcmp (sync, DMR_MS_DATA_SYNC) == 0) && opts->inverted_dmr == 1) )
|
||||
state->dmr_ms_mode = 1;
|
||||
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
if (internalslot == 0)
|
||||
{
|
||||
vc1 = 1;
|
||||
state->DMRvcL = 0; //reset here if jitter/sync forces reset
|
||||
fprintf (stderr, "MS Slot 1 Voice Sync \n");
|
||||
}
|
||||
|
||||
if (internalslot == 1)
|
||||
{
|
||||
vc2 = 1;
|
||||
state->DMRvcR = 0; //reset here if jitter/sync forces reset
|
||||
}
|
||||
|
||||
state->dmr_ms_mode = 1; //set to 1 here??
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
state->dmr_ms_mode = 1; //set to 1 here?
|
||||
|
||||
//don't know if we will catch an RC sync in here or not, should be on VC6 if it occurs
|
||||
if ( (strcmp (rcsync, DMR_RC_DATA_SYNC) == 0) || (strcmp (sync, DMR_RC_DATA_SYNC) == 0) ) //should be in same position as sync
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
//fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc1 = 1;
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
//fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc2 = 1;
|
||||
}
|
||||
fprintf (stderr, "\n "); //21 spaces to line up the sync
|
||||
//processDMRdata (opts, state);
|
||||
state->dmr_ms_rc = 1; //don't know what to do with this, if anything...
|
||||
goto SKIP;
|
||||
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);
|
||||
}
|
||||
|
||||
//check for sync pattern here after collected the rest of the payload, decide what to do with it
|
||||
//if ( (strcmp (sync, DMR_MS_DATA_SYNC) == 0) )
|
||||
//fixed to compensate for inverted signal
|
||||
if ( ((strcmp (sync, DMR_MS_DATA_SYNC) == 0) && opts->inverted_dmr == 0) ||
|
||||
((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) && opts->inverted_dmr == 1) )
|
||||
if (vc == 6)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
//fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | MS Data ", state->color_code);
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc1 = 1;
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
//fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | Data ", state->color_code);
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE ");
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc2 = 1;
|
||||
}
|
||||
//fprintf (stderr, "\n "); //21 spaces to line up the sync
|
||||
//fprintf (stderr, " "); //21 spaces to line up the sync
|
||||
state->dmr_ms_mode = 1; //set to 1 here??
|
||||
processDMRdata (opts, state);
|
||||
skipcount++;
|
||||
//goto SKIP;
|
||||
goto END;
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
fprintf (stderr, "\n");
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
|
||||
if( ( ( ((strcmp (sync, DMR_MS_DATA_SYNC) != 0) && opts->inverted_dmr == 0) ||
|
||||
((strcmp (sync, DMR_MS_VOICE_SYNC) != 0) && opts->inverted_dmr == 1) ) )
|
||||
&& internalslot == activeslot && vc1 < 7)
|
||||
//collect the mi fragment
|
||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
||||
|
||||
{
|
||||
//errors in ms/mono since we skip the other slot
|
||||
// cach_err = dmr_cach (opts, state, cachdata);
|
||||
|
||||
skipcount = 0; //reset skip count if processing voice frames
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0 && opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
vc++;
|
||||
//this is necessary because we need to skip and collect dibits, not just skip them
|
||||
if (vc > 6) goto END;
|
||||
|
||||
if (internalslot == 0 && opts->inverted_dmr == 1)
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
|
||||
if (internalslot == 0 && vc1 == 6) //presumably when full (and no sync issues)
|
||||
{
|
||||
//process voice burst
|
||||
ProcessVoiceBurstSync(opts, state);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
state->dmr_ms_mode == 1;
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
|
||||
//state->directmode = 0; //flag off for testing
|
||||
|
||||
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
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
if (vc1 == 6 && state->payload_algid >= 21)
|
||||
{
|
||||
state->DMRvcL = 0;
|
||||
if (state->payload_mi != 0 && state->payload_algid >= 0x21)
|
||||
{
|
||||
LFSR(state);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
}
|
||||
vc1++;
|
||||
//6 seems optimal for MS, allows to quickly exit and resync if wonky or something
|
||||
if ( (vc1 > 6) || skipcount > 2) //escape to find new sync if deadspins without a renewed voice frame sync inside of loop
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
SKIP:
|
||||
skipDibit (opts, state, 144); //skip to next tdma channel
|
||||
state->dmr_ms_rc = 0;
|
||||
|
||||
//since we are in a repetitive loop, run ncursesPrinter here
|
||||
//since we are in a loop, run ncursesPrinter here
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
ncursesPrinter(opts, state);
|
||||
}
|
||||
|
||||
} // end while loop
|
||||
//reset these variables when exiting MS/DM mode.
|
||||
} // end loop
|
||||
|
||||
END:
|
||||
//get first half payload dibits and store them in the payload for the next repitition
|
||||
skipDibit (opts, state, 144);
|
||||
skipDibit (opts, state, 144); //should we have two of these?
|
||||
|
||||
//CACH + First Half Payload = 12 + 54
|
||||
for (i = 0; i < 66; i++) //66
|
||||
{
|
||||
@@ -516,7 +299,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_ms_mode = 0;
|
||||
state->dmr_ms_rc = 0;
|
||||
state->directmode = 0; //flag off
|
||||
state->DMRvcL = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -525,19 +308,39 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, k, l, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
char ambe_fr4[4][24] = {0}; //shim for playing back direct mode samples where ambe1 is bad, duplicate 2 to 4 and play both to smooth audio
|
||||
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
char ambe_fr4[4][24]; //shim for crappy tdma direct, need more samples to see if this is really a necessary shim or not
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
char m1[4][24];
|
||||
char m2[4][24];
|
||||
char m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
char cachdata[13] = {0};
|
||||
|
||||
//cach
|
||||
char cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
char cc[4];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
unsigned int EmbeddedSignallingOk;
|
||||
char EmbeddedSignalling[16];
|
||||
|
||||
uint8_t emb_ok = 0;
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
uint8_t EmbeddedSignallingOk = 0;
|
||||
|
||||
//add time to mirror sync
|
||||
time_t now;
|
||||
@@ -555,8 +358,8 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
state->dmrburstL = 16; //Use 16 for Voice?
|
||||
|
||||
state->dmrburstL = 16;
|
||||
state->currentslot = 0; //force to slot 0
|
||||
|
||||
dibit_p = state->dmr_payload_p - 90;
|
||||
@@ -594,7 +397,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
//state->dmr_stereo_payload[i+12] = dibit;
|
||||
state->dmr_stereo_payload[i+12] = dibit;
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
@@ -630,12 +433,11 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
@@ -675,86 +477,28 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
z++;
|
||||
|
||||
}
|
||||
//work around to set erroneous PI header values to 0 if K is active
|
||||
if (state->K > 0 || state->K1 > 0)
|
||||
{
|
||||
state->payload_keyid = 0; //just for testing
|
||||
state->payload_keyidR = 0; //just for testing
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if ( (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x68) )
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if ( (state->DMRvcL == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->DMRvcR == 0 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x68) )
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %016llX", state->K1);
|
||||
if (state->K2 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K2);
|
||||
}
|
||||
if (state->K3 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K3);
|
||||
}
|
||||
if (state->K4 != 0)
|
||||
{
|
||||
fprintf(stderr, " %016llX", state->K4);
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
||||
|
||||
state->dmr_ms_mode = 1;
|
||||
state->DMRvcL = 0;
|
||||
fprintf (stderr, "| VC* ");
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
//alg reset
|
||||
//dmr_alg_reset (opts, state);
|
||||
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
|
||||
//state->directmode = 0; //flag off for testing samples
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
@@ -768,25 +512,24 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
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);
|
||||
|
||||
//errors due to skipping other slot
|
||||
// cach_err = dmr_cach (opts, state, cachdata);
|
||||
|
||||
skipDibit (opts, state, 144); //skip to next TDMA slot
|
||||
dmrMS (opts, state); //bootstrap into full TDMA frame
|
||||
|
||||
}
|
||||
|
||||
//simplied to a simple data collector, and then passed on to dmr_data_sync for the usual processing
|
||||
void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, b, c;
|
||||
int dibit;
|
||||
int *dibit_p;
|
||||
unsigned int burst;
|
||||
|
||||
unsigned char MSCach[24] = {0}; //12 dibits = 24 bits
|
||||
unsigned char MSSync[48] = {0}; //24 dibits = 48 bits
|
||||
unsigned char MSSlot[20] = {0}; //10 dibits = 20 bits
|
||||
unsigned char MSBurst[5] = {0};
|
||||
int cachInterleave[24] = {0, 7, 8, 9, 1, 10, 11, 12, 2, 13, 14, 15, 3, 16, 4, 17, 18, 19, 5, 20, 21, 22, 6, 23};
|
||||
|
||||
//add time to mirror sync
|
||||
time_t now;
|
||||
@@ -804,8 +547,7 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
return curr;
|
||||
}
|
||||
b = 0;
|
||||
c = 0;
|
||||
|
||||
|
||||
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
||||
dibit_p = state->dmr_payload_p - 90;
|
||||
@@ -813,94 +555,25 @@ 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);
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
//load cach
|
||||
if (i < 12)
|
||||
{
|
||||
MSCach[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
|
||||
MSCach[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
}
|
||||
//load slot, first half
|
||||
if (i > 60 && i < 66)
|
||||
{
|
||||
MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1
|
||||
MSSlot[(b*2)+1] = (1 & dibit); // bit
|
||||
b++;
|
||||
}
|
||||
//load sync
|
||||
if (i > 66)
|
||||
{
|
||||
MSSync[(c*2)] = (1 & (dibit >> 1)); // bit 1
|
||||
MSSync[(c*2)+1] = (1 & dibit); // bit 0
|
||||
c++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < 54; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2);
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
//load slot, second half
|
||||
if (i < 6)
|
||||
{
|
||||
MSSlot[(b*2)] = (1 & (dibit >> 1)); // bit 1
|
||||
MSSlot[(b*2)+1] = (1 & dibit); // bit
|
||||
b++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//state->directmode = 0; //flag off for testing
|
||||
|
||||
//with FEC fix, now we can (hopefully) feel confident in running MS data
|
||||
if (1 == 1) //opts->payload == 1 && state->directmode == 0
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE ");
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE/MONO ");
|
||||
}
|
||||
|
||||
// decode and correct cach and slot
|
||||
// golay (20,8) hamming-weight of 6 reliably corrects at most 2 bit-errors
|
||||
int cach_okay = -1;
|
||||
if ( Hamming_7_4_decode (MSCach) )
|
||||
{
|
||||
cach_okay = 1;
|
||||
}
|
||||
if (cach_okay == 1)
|
||||
{
|
||||
//fprintf (stderr, "CACH Okay ");
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf (stderr, "CACH ERR ");
|
||||
if (opts->aggressive_framesync == 1) //may not worry about it on data
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
int slot_okay = -1;
|
||||
if(Golay_20_8_decode(MSSlot))
|
||||
{
|
||||
slot_okay = 1;
|
||||
}
|
||||
if (slot_okay == 1)
|
||||
{
|
||||
//fprintf (stderr, "Slot Okay ");
|
||||
}
|
||||
else goto END;
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE/MONO ");
|
||||
|
||||
|
||||
sprintf(state->slot1light, "%s", "");
|
||||
@@ -910,33 +583,23 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_stereo = 1;
|
||||
state->dmr_ms_mode = 1;
|
||||
|
||||
//with FEC fix, now we can (hopefully) feel confident in running MS data
|
||||
if (1 == 1) //opts->payload == 1 && state->directmode == 0
|
||||
{
|
||||
processDMRdata (opts, state);
|
||||
}
|
||||
|
||||
END:
|
||||
if (slot_okay != 1 || cach_okay != 1)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| ** CACH or Burst Type FEC ERR ** ");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
dmr_data_sync (opts, state);
|
||||
|
||||
state->dmr_stereo = 0;
|
||||
state->dmr_ms_mode = 0;
|
||||
state->directmode = 0; //flag off
|
||||
|
||||
//get potential first half payload dibits and store them in the payload for the next repitition, MS voice or data.
|
||||
skipDibit (opts, state, 144);
|
||||
|
||||
//should just be loaded in the dmr_payload_buffer instead now
|
||||
for (i = 0; i < 144; i++) //66
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
}
|
||||
//CACH + First Half Payload = 12 + 54
|
||||
for (i = 0; i < 66; i++) //66
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
369
src/dmr_pdu.c
Normal file
369
src/dmr_pdu.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_bs.c
|
||||
* DMR Data (1/2, 3/4, 1) PDU Decoding
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
//unified DMR multiblock PDU message handler (LRRP, etc)
|
||||
#include "dsd.h"
|
||||
|
||||
char * getTimeL(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
char * getDateL(void) {
|
||||
char datename[120];
|
||||
char * curr2;
|
||||
struct tm * to;
|
||||
time_t t;
|
||||
t = time(NULL);
|
||||
to = localtime( & t);
|
||||
strftime(datename, sizeof(datename), "%Y/%m/%d", to);
|
||||
curr2 = strtok(datename, " ");
|
||||
return curr2;
|
||||
}
|
||||
|
||||
void dmr_pdu (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[])
|
||||
{
|
||||
|
||||
int message_legnth = 0;
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t blocks = state->data_header_blocks[slot] - 1; //subtract 1 for the relevant value in the calc below
|
||||
uint8_t padding = state->data_header_padding[slot];
|
||||
uint8_t lrrp_conf = 0;
|
||||
|
||||
lrrp_conf = dmr_lrrp_check (opts, state, DMR_PDU);
|
||||
|
||||
//maybe one day we will have more things to do here
|
||||
state->data_conf_data[slot] = 0; //flag off confirmed data after processing it
|
||||
|
||||
}
|
||||
|
||||
//The contents of this function are mostly my reversed engineered efforts by observing DSDPlus output and matching data bytes
|
||||
//combined with a few external sources such as OK-DMR for some token values and extra data values (rad and alt)
|
||||
//this is by no means an extensive LRRP list and is prone to error (unless somebody has the manual or something)
|
||||
uint8_t dmr_lrrp_check (dsd_opts * opts, dsd_state * state, uint8_t DMR_PDU[])
|
||||
{
|
||||
int i, j;
|
||||
uint8_t message_len = 0;
|
||||
uint8_t slot = state->currentslot;
|
||||
uint8_t blocks = state->data_header_blocks[slot] - 1;
|
||||
uint8_t padding = state->data_header_padding[slot];
|
||||
uint8_t lrrp_confidence = 0; //variable to increment based on number of tokens found, the more, the higher the confidence level
|
||||
|
||||
//source/dest and ports
|
||||
uint32_t source = 0;
|
||||
uint32_t dest = 0;
|
||||
uint16_t port_s = 0;
|
||||
uint16_t port_d = 0;
|
||||
|
||||
//time
|
||||
uint16_t year = 0;
|
||||
uint16_t month = 0;
|
||||
uint16_t day = 0;
|
||||
uint16_t hour = 0;
|
||||
uint16_t minute = 0;
|
||||
uint16_t second = 0;
|
||||
|
||||
//lat-long-radius-alt
|
||||
uint32_t lat = 0;
|
||||
uint8_t lat_sign = 0;
|
||||
uint32_t lon = 0;
|
||||
uint16_t rad = 0;
|
||||
uint8_t alt = 0;
|
||||
double lat_unit = (double)180/(double)4294967295;
|
||||
double lon_unit = (double)360/(double)4294967295;
|
||||
|
||||
//speed/velocity
|
||||
uint16_t vel = 0;
|
||||
double velocity = 0;
|
||||
uint8_t vel_set = 0;
|
||||
|
||||
//track, direction, degrees
|
||||
uint8_t degrees = 0;
|
||||
uint8_t deg_set = 0;
|
||||
|
||||
//triggered information report
|
||||
uint8_t report = 0;
|
||||
uint8_t pot_report = 0; //potential report by findind 0x0D and backtracking a few bytes
|
||||
|
||||
i = 0; //watch DMR_PDU[10] closely for a 'report' token
|
||||
//start looking for tokens (using my best understanding of the ok-dmr library xml and python files)
|
||||
for (i; i < ( ((blocks+1)*16) - (padding+4) ); i++) //need to change the 16, or entire thing? or who cares lol just keep looking
|
||||
{
|
||||
|
||||
switch(DMR_PDU[i]){
|
||||
case 0x0C: //LRRP_TriggeredLocationReport
|
||||
if (source == 0)
|
||||
{
|
||||
source = (DMR_PDU[i+1] << 16 ) + (DMR_PDU[i+2] << 8) + DMR_PDU[i+3];
|
||||
dest = (DMR_PDU[i+5] << 16 ) + (DMR_PDU[i+6] << 8) + DMR_PDU[i+7];
|
||||
port_s = (DMR_PDU[i+8] << 8) + DMR_PDU[i+9];
|
||||
port_d = (DMR_PDU[i+10] << 8) + DMR_PDU[i+11];
|
||||
i += 11;
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
//may need more 'report' types to trigger various scenarios
|
||||
//disable all but 0x1F if issues or falsing happens often
|
||||
//case 0x1D: //ARRP_TriggeredInformationAnswer_NCDT
|
||||
//case 0x1E: //ARRP_TriggeredInformationReport = FALSE?
|
||||
//case 0x25: //ARRP_UnsolicitedInformationReport_NCDT = (0x25, True, "")
|
||||
case 0x13: //LRRP_UnsolicitedLocationReport_NCDT
|
||||
case 0x15: //LRRP_LocationProtocolReport_NCDT
|
||||
case 0x21: //ARRP_TriggeredInformationStopRequest_NCDT
|
||||
case 0x1F: //ARRP_TriggeredInformationReport_NCDT
|
||||
if (report == 0)
|
||||
{
|
||||
report = DMR_PDU[i];
|
||||
i += 1;
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
//0x0D always seems to follow 0x1F or other 'report' types two/three bytes later
|
||||
case 0x0D: //message len indicator //LRRP_TriggeredLocationReport_NCDT
|
||||
if (report > 0 && message_len == 0)
|
||||
{
|
||||
message_len = DMR_PDU[i+1];
|
||||
i += 1;
|
||||
lrrp_confidence++;
|
||||
}
|
||||
else if (message_len == 0)
|
||||
{
|
||||
if (i > 3)
|
||||
{
|
||||
if (DMR_PDU[i-3] > 0) pot_report = DMR_PDU[i-3];
|
||||
if (pot_report < 0x27)
|
||||
{
|
||||
report = pot_report;
|
||||
message_len = DMR_PDU[i+1];
|
||||
i += 1;
|
||||
//no lrrp_confidence on speculative reporting, but will print it as such.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
//RESULT TOKEN or Request ID!
|
||||
case 0x23: //this value has been seen after the 0x0D message len, appears to be a 2-byte value, was tripping a false on time stamp
|
||||
i += 2;
|
||||
break;
|
||||
//answer and report tokens
|
||||
case 0x51: //circle-2d
|
||||
case 0x54: //circle-3d
|
||||
case 0x55: //circle-3d <- false positives on one sample, so either an earlier token occurred (that we don't have) or just random data?
|
||||
if (message_len > 0 && lat == 0)
|
||||
{
|
||||
if (DMR_PDU[i+1] & 0x80) lat_sign = 1;
|
||||
lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
|
||||
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
|
||||
rad = (DMR_PDU[i+9] << 8) + DMR_PDU[i+10];
|
||||
i += 10; //double check
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x34: //Time Interval Periodic Trigger (timestamp)
|
||||
case 0x35: //Time Interval Periodic Trigger (timestamp)
|
||||
if (message_len > 0 && year == 0)
|
||||
{
|
||||
year = (DMR_PDU[i+1] << 6) + (DMR_PDU[i+2] >> 2);
|
||||
month = ((DMR_PDU[i+2] & 0x3) << 2) + ((DMR_PDU[i+3] & 0xC0) >> 6);
|
||||
day = ((DMR_PDU[i+3] & 0x30) >> 1) + ((DMR_PDU[i+3] & 0x0E) >> 1);
|
||||
hour = ((DMR_PDU[i+3] & 0x01) << 4) + ((DMR_PDU[i+4] & 0xF0) >> 4);
|
||||
minute = ((DMR_PDU[i+4] & 0x0F) << 2) + ((DMR_PDU[i+5] & 0xC0) >> 6);
|
||||
second = (DMR_PDU[i+5] & 0x3F);
|
||||
i += 5;
|
||||
//sanity check
|
||||
if (year > 2000 && year < 2025) lrrp_confidence++;
|
||||
if (year > 2025 || year < 2000) year = 0; //needs future proofing
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x66: //point-2d
|
||||
if (message_len > 0 && lat == 0)
|
||||
{
|
||||
if (DMR_PDU[i+1] & 0x80) lat_sign = 1;
|
||||
lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
|
||||
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
|
||||
i += 8; //check
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
case 0x69: //point-3d
|
||||
case 0x6A: //point-3d
|
||||
if (message_len > 0 && lat == 0)
|
||||
{
|
||||
if (DMR_PDU[i+1] & 0x80) lat_sign = 1;
|
||||
lat = ( ( ((DMR_PDU[i+1] & 0x7F ) << 24 ) + (DMR_PDU[i+2] << 16) + (DMR_PDU[i+3] << 8) + DMR_PDU[i+4]) * 1 );
|
||||
lon = ( ( (DMR_PDU[i+5] << 24 ) + (DMR_PDU[i+6] << 16) + (DMR_PDU[i+7] << 8) + DMR_PDU[i+8]) * 1 );
|
||||
alt = DMR_PDU[i+9];
|
||||
i += 9; //check
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
case 0x36: //protocol-version
|
||||
i += 1;
|
||||
//lrrp_confidence++;
|
||||
break;
|
||||
//speed/velocity
|
||||
case 0x70: //speed-virt
|
||||
case 0x6C: //speed-hor
|
||||
if (message_len > 0 && vel_set == 0)
|
||||
{
|
||||
vel = (DMR_PDU[i+1] << 8) + DMR_PDU[i+2]; //don't think this is meant to be shifted, but doing it anyways for comparison
|
||||
velocity = ( ((double)( (DMR_PDU[i+1] ) + DMR_PDU[i+2] )) / ( (double)128));
|
||||
vel_set = 1;
|
||||
i += 2;
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
case 0x56: //direction-hor
|
||||
if (message_len > 0 && deg_set == 0)
|
||||
{
|
||||
degrees = DMR_PDU[i+1] * 2;
|
||||
deg_set = 1;
|
||||
i += 1;
|
||||
lrrp_confidence++;
|
||||
}
|
||||
break;
|
||||
//below all unknown
|
||||
case 0x37: //result
|
||||
case 0x38: //result
|
||||
case 0x39: //result 'operations error'? attributes 0x22?
|
||||
case 0x6B: //unknown-uint8
|
||||
case 0x65: //lev-conf
|
||||
default:
|
||||
//do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (report && message_len > 0)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf (stderr, "\n LRRP Confidence: %d - Message Len: %d", lrrp_confidence, message_len);
|
||||
if (lrrp_confidence >= 3) //find the sweet magical number
|
||||
{
|
||||
//now we can open our lrrp file and write to it as well
|
||||
FILE * pFile; //file pointer
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
//open file by name that is supplied in the ncurses terminal, or cli
|
||||
pFile = fopen (opts->lrrp_out_file, "a");
|
||||
//write current date/time if not present in LRRP data
|
||||
if (!year) fprintf (pFile, "%s\t", getDateL() ); //current date, only add this IF no included timestamp in LRRP data?
|
||||
if (!year) fprintf (pFile, "%s\t", getTimeL() ); //current timestamp, only add this IF no included timestamp in LRRP data?
|
||||
if (year) fprintf (pFile, "%04d/%02d/%02d\t%02d:%02d:%02d\t", year, month, day, hour, minute, second); //add timestamp from decoded audio if available
|
||||
//write data header source (or destination?) if not available in lrrp data
|
||||
if (!source) fprintf (pFile, "%08lld\t", state->dmr_lrrp_source[state->currentslot]); //source address from data header
|
||||
if (source) fprintf (pFile, "%08d\t", source); //add source form decoded audio if available, else its from the header
|
||||
}
|
||||
|
||||
if (pot_report)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
|
||||
}
|
||||
if (report)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Report: 0x%02X", report);
|
||||
if (report == 0x1F) fprintf (stderr, " ARRP_TriggeredInformationReport_NCDT "); //customize later when more is learned
|
||||
if (report == 0x21) fprintf (stderr, " ARRP_TriggeredInformationStopRequest_NCDT ");
|
||||
if (report == 0x22) fprintf (stderr, " ARRP_TriggeredInformationStopAnswer ");
|
||||
if (report == 0x25) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT ");
|
||||
if (report == 0x26) fprintf (stderr, " ARRP_UnsolicitedInformationReport_NCDT ");
|
||||
if (report == 0x27) fprintf (stderr, " ARRP_InformationProtocolRequest_NCDT ");
|
||||
if (report == 0x13) fprintf (stderr, " LRRP_UnsolicitedLocationReport_NCDT ");
|
||||
|
||||
}
|
||||
if (source)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Source: %08d - %04d", source, port_s);
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Destination: %08d - %04d", dest, port_d);
|
||||
|
||||
}
|
||||
if (year)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " LRRP - Time: ");
|
||||
fprintf (stderr, " %04d.%02d.%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
|
||||
|
||||
}
|
||||
if (lat)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
if (lat_sign) //print a '-' in front of the value
|
||||
fprintf (stderr, " LRRP - Lat: -%.5lf", (double)lat * lat_unit);
|
||||
else fprintf (stderr, " LRRP - Lat: %.5lf", (double)lat * lat_unit);
|
||||
fprintf (stderr, " Lon: %.5lf", (double)lon * lon_unit);
|
||||
if (lat_sign)
|
||||
fprintf (stderr, " (-%.5lf, %.5lf)", (double)lat * lat_unit , (double)lon * lon_unit);
|
||||
else fprintf (stderr, " (%.5lf, %.5lf)", (double)lat * lat_unit , (double)lon * lon_unit);
|
||||
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
if (lat_sign) fprintf (pFile, "-");
|
||||
fprintf (pFile, "%.5lf\t", (double)lat * lat_unit);
|
||||
fprintf (pFile, "%.5lf\t", (double)lon * lon_unit);
|
||||
}
|
||||
|
||||
}
|
||||
if (rad)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " LRRP - Radius: %d", rad); //unsure of 'units' or calculation for radius (meters?)
|
||||
}
|
||||
if (alt)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " LRRP - Altitude: %d", alt); //unsure of 'units' or calculation for alt (meters?)
|
||||
}
|
||||
if (vel_set)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " LRRP - Velocity: %.4lf m/s %.4lf km/h %.4lf mph", velocity, (3.6 * velocity), (2.2369 * velocity));
|
||||
if (opts->lrrp_file_output == 1) fprintf (pFile, "%.3lf\t ", (velocity * 3.6) );
|
||||
}
|
||||
if (deg_set)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " LRRP - Track: %d Degrees", degrees);
|
||||
if (opts->lrrp_file_output == 1) fprintf (pFile, "%d\t",degrees);
|
||||
}
|
||||
|
||||
//close open file
|
||||
if (opts->lrrp_file_output == 1)
|
||||
{
|
||||
fprintf (pFile, "\n");
|
||||
fclose (pFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (pot_report)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, " Potential ARRP/LRRP Report (Debug): 0x%02X", report);
|
||||
}
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
|
||||
return (lrrp_confidence);
|
||||
}
|
||||
136
src/dmr_pi.c
Normal file
136
src/dmr_pi.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_pi.c
|
||||
* DMR Privacy Indicator and LFSR Function
|
||||
*
|
||||
* LFSR code courtesy of https://github.com/mattames/LFSR/
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void dmr_pi (dsd_opts * opts, dsd_state * state, uint8_t PI_BYTE[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors)
|
||||
{
|
||||
|
||||
if((IrrecoverableErrors == 0))
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
|
||||
if (0 == 0)
|
||||
{
|
||||
state->payload_algid = PI_BYTE[0];
|
||||
state->payload_keyid = PI_BYTE[2];
|
||||
}
|
||||
|
||||
state->payload_mi = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
|
||||
if (state->payload_algid < 0x26)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 1");
|
||||
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (state->payload_algid >= 0x26)
|
||||
{
|
||||
if (0 == 0)
|
||||
{
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
state->payload_mi = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
if (0 == 0)
|
||||
{
|
||||
state->payload_algidR = PI_BYTE[0];
|
||||
state->payload_keyidR = PI_BYTE[2];
|
||||
}
|
||||
|
||||
state->payload_miR = ( ((PI_BYTE[3]) << 24) + ((PI_BYTE[4]) << 16) + ((PI_BYTE[5]) << 8) + (PI_BYTE[6]) );
|
||||
if (state->payload_algidR < 0x26)
|
||||
{
|
||||
fprintf (stderr, "%s ", KYEL);
|
||||
fprintf (stderr, "\n Slot 2");
|
||||
fprintf (stderr, " DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algidR, state->payload_keyidR, state->payload_miR);
|
||||
fprintf (stderr, "%s ", KNRM);
|
||||
}
|
||||
|
||||
if (state->payload_algidR >= 0x26)
|
||||
{
|
||||
if (0== 0)
|
||||
{
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyidR = 0;
|
||||
state->payload_miR = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int lfsr = 0;
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
lfsr = state->payload_mi;
|
||||
}
|
||||
else lfsr = state->payload_miR;
|
||||
|
||||
uint8_t cnt = 0;
|
||||
|
||||
for(cnt=0;cnt<32;cnt++)
|
||||
{
|
||||
// Polynomial is C(x) = x^32 + x^4 + x^2 + 1
|
||||
int bit = ((lfsr >> 31) ^ (lfsr >> 3) ^ (lfsr >> 1)) & 0x1;
|
||||
lfsr = (lfsr << 1) | (bit);
|
||||
}
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
if (1 == 1)
|
||||
{
|
||||
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, " Next MI: 0x%08X", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
state->payload_mi = lfsr;
|
||||
}
|
||||
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
if (1 == 1)
|
||||
{
|
||||
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, " Next MI: 0x%08X", lfsr);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
state->payload_miR = lfsr;
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
#include "p25p1_check_hdu.h"
|
||||
|
||||
void ProcessDMR (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t Frame;
|
||||
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL;
|
||||
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL;
|
||||
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameRC = NULL; //Reverse Test for MS Backwards
|
||||
|
||||
int *errs;
|
||||
int *errs2;
|
||||
unsigned long long int k;
|
||||
int x;
|
||||
k = 0;
|
||||
|
||||
TSVoiceSupFrameL = &state->TS1SuperFrame;
|
||||
TSVoiceSupFrameR = &state->TS2SuperFrame;
|
||||
|
||||
int 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
|
||||
};
|
||||
|
||||
|
||||
if ( (state->currentslot == 0 && state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->currentslot == 0 && state->K > 0 && state->M == 1) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
k = Pr[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
|
||||
for(Frame = 0; Frame < 6; Frame++)
|
||||
{
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 48; j++)
|
||||
{
|
||||
x = ( ((k << j) & 0x800000000000) >> 47 );
|
||||
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (state->currentslot == 1 && state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x10) ||
|
||||
(state->currentslot == 1 && state->K > 0 && state->M == 1) )
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " PrK %lld", state->K);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
k = Pr[state->K];
|
||||
k = ( ((k & 0xFF0F) << 32 ) + (k << 16) + k );
|
||||
|
||||
for(Frame = 0; Frame < 6; Frame++)
|
||||
{
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 48; j++)
|
||||
{
|
||||
x = ( ((k << j) & 0x800000000000) >> 47 );
|
||||
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (state->currentslot == 0 && state->K1 > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x68) ||
|
||||
(state->currentslot == 0 && state->K1 > 0 && state->M == 1) )
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
|
||||
unsigned long long int k1 = state->K1;
|
||||
unsigned long long int k2 = state->K2;
|
||||
unsigned long long int k3 = state->K3;
|
||||
unsigned long long int k4 = state->K4;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %010llX", k1);
|
||||
|
||||
int T_Key[256] = {0};
|
||||
int pN[882] = {0};
|
||||
|
||||
int len = 0;
|
||||
|
||||
if (k2 == 0)
|
||||
{
|
||||
len = 39;
|
||||
k1 = k1 << 24;
|
||||
}
|
||||
if (k2 != 0)
|
||||
{
|
||||
len = 127;
|
||||
fprintf(stderr, " %016llX", k2);
|
||||
}
|
||||
if (k4 != 0)
|
||||
{
|
||||
len = 255;
|
||||
fprintf(stderr, " %016llX", k3);
|
||||
fprintf(stderr, " %016llX", k4);
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
|
||||
}
|
||||
|
||||
for (i = 0; i < 882; i++)
|
||||
{
|
||||
pN[i] = T_Key[pos];
|
||||
pos++;
|
||||
if (pos > len)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
for(Frame = 0; Frame < 6; Frame++)
|
||||
{
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 49; j++)
|
||||
{
|
||||
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( (state->currentslot == 1 && state->K1 > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fidR == 0x68) ||
|
||||
(state->currentslot == 1 && state->K1 > 0 && state->M == 1) )
|
||||
{
|
||||
|
||||
int pos = 0;
|
||||
|
||||
unsigned long long int k1 = state->K1;
|
||||
unsigned long long int k2 = state->K2;
|
||||
unsigned long long int k3 = state->K3;
|
||||
unsigned long long int k4 = state->K4;
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
fprintf(stderr, " SPT %010llX", k1);
|
||||
|
||||
int T_Key[256] = {0};
|
||||
int pN[882] = {0};
|
||||
|
||||
int len = 0;
|
||||
|
||||
if (k2 == 0)
|
||||
{
|
||||
len = 39;
|
||||
k1 = k1 << 24;
|
||||
}
|
||||
if (k2 != 0)
|
||||
{
|
||||
len = 127;
|
||||
fprintf(stderr, " %016llX", k2);
|
||||
}
|
||||
if (k4 != 0)
|
||||
{
|
||||
len = 255;
|
||||
fprintf(stderr, " %016llX", k3);
|
||||
fprintf(stderr, " %016llX", k4);
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
T_Key[i] = ( ((k1 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+64] = ( ((k2 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+128] = ( ((k3 << i) & 0x8000000000000000) >> 63 );
|
||||
T_Key[i+192] = ( ((k4 << i) & 0x8000000000000000) >> 63 );
|
||||
}
|
||||
|
||||
for (i = 0; i < 882; i++)
|
||||
{
|
||||
pN[i] = T_Key[pos];
|
||||
pos++;
|
||||
if (pos > len)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
for(Frame = 0; Frame < 6; Frame++)
|
||||
{
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 49; j++)
|
||||
{
|
||||
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j] ^= pN[pos];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
|
||||
for(Frame = 0; Frame < 6; Frame++) //6
|
||||
{
|
||||
/* 1 DMR frame contains 3 AMBE voice samples */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
|
||||
errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
|
||||
state->errs = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
|
||||
state->errs2 = TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
|
||||
TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
|
||||
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
PrintAMBEData(opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
|
||||
}
|
||||
|
||||
//quick enc toggle to determine whether or not to play enc traffic
|
||||
int enc_bit = 0;
|
||||
enc_bit = (state->dmr_so >> 6) & 0x1;
|
||||
if (enc_bit == 1)
|
||||
{
|
||||
state->dmr_encL = 1;
|
||||
}
|
||||
else state->dmr_encL = 0;
|
||||
|
||||
if (state->K != 0 || state->K1 != 0)
|
||||
{
|
||||
state->dmr_encL = 0;
|
||||
}
|
||||
|
||||
//quick test to determine whether or not to run the next few steps below
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveAmbe2450Data (opts, state, TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
|
||||
}
|
||||
|
||||
state->debug_audio_errors += *errs2;
|
||||
|
||||
processAudio(opts, state);
|
||||
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
|
||||
if (opts->audio_out == 1) //opts->audio_out == 1
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
} //second bracket for the test enc condition
|
||||
} /* End for(i = 0; i < 3; i++) */
|
||||
} /* End for(Frame = 0; Frame < 6; Frame++) */
|
||||
} //End if Current Slot == 0
|
||||
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
|
||||
for(Frame = 0; Frame < 6; Frame++)
|
||||
{
|
||||
/* 1 DMR frame contains 3 AMBE voice samples */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
errs = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
|
||||
errs2 = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
|
||||
state->errs = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
|
||||
state->errs2 = TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
|
||||
|
||||
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
|
||||
TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
|
||||
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
PrintAMBEData(opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
|
||||
}
|
||||
|
||||
//quick enc toggle to determine whether or not to play enc traffic
|
||||
int enc_bit = 0;
|
||||
enc_bit = (state->dmr_soR >> 6) & 0x1;
|
||||
if (enc_bit == 1)
|
||||
{
|
||||
state->dmr_encR = 1;
|
||||
}
|
||||
else state->dmr_encR = 0;
|
||||
|
||||
if (state->K != 0 || state->K1 != 0)
|
||||
{
|
||||
state->dmr_encR = 0;
|
||||
}
|
||||
|
||||
//quick test to determine whether or not to run the next few steps below
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveAmbe2450Data (opts, state, TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
|
||||
}
|
||||
|
||||
state->debug_audio_errors += *errs2;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} /* End for(i = 0; i < 3; i++) */
|
||||
} /* End for(Frame = 0; Frame < 6; Frame++) */
|
||||
} //End if Current Slot == 1
|
||||
|
||||
|
||||
} /* End ProcessDMR */
|
||||
/* End of file */
|
||||
2939
src/dmr_sync.c
2939
src/dmr_sync.c
File diff suppressed because it is too large
Load Diff
302
src/dmr_utils.c
Normal file
302
src/dmr_utils.c
Normal file
@@ -0,0 +1,302 @@
|
||||
//DMR CRC/Utility Functions
|
||||
//Original File - dmr_sync.c
|
||||
//ConvertBitIntoBytes, ComputeCrcCCITT, ComputeCrc5Bit, ComputeAndCorrectFullLinkControlCrc, CRC32, CRC9
|
||||
//Original Source - https://github.com/LouisErigHerve/dsd
|
||||
|
||||
//Additional Functions
|
||||
//Hamming17123, crc8, crc8ok functions
|
||||
//Original Souce - https://github.com/boatbod/op25
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
// A Hamming (17,12,3) Check for completed SLC message
|
||||
bool Hamming17123(uint8_t* d)
|
||||
{
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
|
||||
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
|
||||
bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
|
||||
bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
|
||||
bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
|
||||
|
||||
// Compare these with the actual bits
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[12]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[13]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[14]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[15]) ? 0x08U : 0x00U;
|
||||
n |= (c4 != d[16]) ? 0x10U : 0x00U;
|
||||
|
||||
switch (n) {
|
||||
// Parity bit errors
|
||||
case 0x01U: d[12] = !d[12]; return true;
|
||||
case 0x02U: d[13] = !d[13]; return true;
|
||||
case 0x04U: d[14] = !d[14]; return true;
|
||||
case 0x08U: d[15] = !d[15]; return true;
|
||||
case 0x10U: d[16] = !d[16]; return true;
|
||||
|
||||
// Data bit errors
|
||||
case 0x1BU: d[0] = !d[0]; return true;
|
||||
case 0x1FU: d[1] = !d[1]; return true;
|
||||
case 0x17U: d[2] = !d[2]; return true;
|
||||
case 0x07U: d[3] = !d[3]; return true;
|
||||
case 0x0EU: d[4] = !d[4]; return true;
|
||||
case 0x1CU: d[5] = !d[5]; return true;
|
||||
case 0x11U: d[6] = !d[6]; return true;
|
||||
case 0x0BU: d[7] = !d[7]; return true;
|
||||
case 0x16U: d[8] = !d[8]; return true;
|
||||
case 0x05U: d[9] = !d[9]; return true;
|
||||
case 0x0AU: d[10] = !d[10]; return true;
|
||||
case 0x14U: d[11] = !d[11]; return true;
|
||||
|
||||
// No bit errors
|
||||
case 0x00U: return true;
|
||||
|
||||
// Unrecoverable errors
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t crc8(uint8_t bits[], unsigned int len)
|
||||
{
|
||||
uint8_t crc=0;
|
||||
unsigned int K = 8;
|
||||
uint8_t poly[9] = {1,0,0,0,0,0,1,1,1}; // crc8 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;
|
||||
}
|
||||
|
||||
bool crc8_ok(uint8_t bits[], unsigned int len)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
for (unsigned int i=0; i < 8; i++) {
|
||||
crc = (crc << 1) + bits[len+i];
|
||||
}
|
||||
return (crc == crc8(bits,len));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief : This function compute the CRC-CCITT of the DMR data
|
||||
* by using the polynomial x^16 + x^12 + x^5 + 1
|
||||
*
|
||||
* @param Input : A buffer pointer of the DMR data (80 bytes)
|
||||
*
|
||||
* @return The 16 bit CRC
|
||||
*/
|
||||
|
||||
uint16_t ComputeCrcCCITT(uint8_t * DMRData)
|
||||
{
|
||||
uint32_t i;
|
||||
uint16_t CRC = 0x0000; /* Initialization value = 0x0000 */
|
||||
/* Polynomial x^16 + x^12 + x^5 + 1
|
||||
* Normal = 0x1021
|
||||
* Reciprocal = 0x0811
|
||||
* Reversed = 0x8408
|
||||
* Reversed reciprocal = 0x8810 */
|
||||
uint16_t Polynome = 0x1021;
|
||||
for(i = 0; i < 80; i++)
|
||||
{
|
||||
if(((CRC >> 15) & 1) ^ (DMRData[i] & 1))
|
||||
{
|
||||
CRC = (CRC << 1) ^ Polynome;
|
||||
}
|
||||
else
|
||||
{
|
||||
CRC <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invert the CRC */
|
||||
CRC ^= 0xFFFF;
|
||||
|
||||
/* Return the CRC */
|
||||
return CRC;
|
||||
} /* End ComputeCrcCCITT() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function compute the CRC-24 bit of the full
|
||||
* link control by using the Reed-Solomon(12,9) FEC
|
||||
*
|
||||
* @param FullLinkControlDataBytes : A buffer pointer of the DMR data bytes (12 bytes)
|
||||
*
|
||||
* @param CRCComputed : A 32 bit pointer where the computed CRC 24-bit will be stored
|
||||
*
|
||||
* @param CRCMask : The 24 bit CRC mask to apply
|
||||
*
|
||||
* @return 0 = CRC error
|
||||
* 1 = CRC is correct
|
||||
*/
|
||||
|
||||
uint32_t ComputeAndCorrectFullLinkControlCrc(uint8_t * FullLinkControlDataBytes, uint32_t * CRCComputed, uint32_t CRCMask)
|
||||
{
|
||||
uint32_t i;
|
||||
rs_12_9_codeword_t VoiceLCHeaderStr;
|
||||
rs_12_9_poly_t syndrome;
|
||||
uint8_t errors_found = 0;
|
||||
rs_12_9_correct_errors_result_t result = RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND;
|
||||
uint32_t CrcIsCorrect = 0;
|
||||
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
VoiceLCHeaderStr.data[i] = FullLinkControlDataBytes[i];
|
||||
|
||||
/* Apply CRC mask on each 3 last bytes
|
||||
* of the full link control */
|
||||
if(i == 9)
|
||||
{
|
||||
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 16);
|
||||
}
|
||||
else if(i == 10)
|
||||
{
|
||||
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask >> 8);
|
||||
}
|
||||
else if(i == 11)
|
||||
{
|
||||
VoiceLCHeaderStr.data[i] ^= (uint8_t)(CRCMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
}
|
||||
|
||||
/* Check and correct the full link LC control with Reed Solomon (12,9) FEC */
|
||||
rs_12_9_calc_syndrome(&VoiceLCHeaderStr, &syndrome);
|
||||
if(rs_12_9_check_syndrome(&syndrome) != 0) result = rs_12_9_correct_errors(&VoiceLCHeaderStr, &syndrome, &errors_found);
|
||||
|
||||
/* Reconstitue the CRC */
|
||||
*CRCComputed = (uint32_t)((VoiceLCHeaderStr.data[9] << 16) & 0xFF0000);
|
||||
*CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[10] << 8) & 0x00FF00);
|
||||
*CRCComputed |= (uint32_t)((VoiceLCHeaderStr.data[11] << 0) & 0x0000FF);
|
||||
|
||||
if((result == RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND) ||
|
||||
(result == RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED))
|
||||
{
|
||||
//fprintf(stderr, "CRC OK : 0x%06X\n", *CRCComputed);
|
||||
CrcIsCorrect = 1;
|
||||
|
||||
/* Reconstitue full link control data after FEC correction */
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
FullLinkControlDataBytes[i] = VoiceLCHeaderStr.data[i];
|
||||
|
||||
/* Apply CRC mask on each 3 last bytes
|
||||
* of the full link control */
|
||||
if(i == 9)
|
||||
{
|
||||
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 16);
|
||||
}
|
||||
else if(i == 10)
|
||||
{
|
||||
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask >> 8);
|
||||
}
|
||||
else if(i == 11)
|
||||
{
|
||||
FullLinkControlDataBytes[i] ^= (uint8_t)(CRCMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr, "CRC ERROR : 0x%06X\n", *CRCComputed);
|
||||
CrcIsCorrect = 0;
|
||||
}
|
||||
|
||||
/* Return the CRC status */
|
||||
return CrcIsCorrect;
|
||||
} /* End ComputeAndCorrectFullLinkControlCrc() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function compute the 5 bit CRC of the DMR voice burst data
|
||||
* See ETSI TS 102 361-1 chapter B.3.11
|
||||
*
|
||||
* @param Input : A buffer pointer of the DMR data (72 bytes)
|
||||
*
|
||||
* @return The 5 bit CRC
|
||||
*/
|
||||
|
||||
uint8_t ComputeCrc5Bit(uint8_t * DMRData)
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t Buffer[9];
|
||||
uint32_t Sum;
|
||||
uint8_t CRC = 0;
|
||||
|
||||
/* Convert the 72 bit into 9 bytes */
|
||||
k = 0;
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
Buffer[i] = 0;
|
||||
for(j = 0; j < 8; j++)
|
||||
{
|
||||
Buffer[i] = Buffer[i] << 1;
|
||||
Buffer[i] = Buffer[i] | DMRData[k++];
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all 9 bytes */
|
||||
Sum = 0;
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
Sum += (uint32_t)Buffer[i];
|
||||
}
|
||||
|
||||
/* Sum MOD 31 = CRC */
|
||||
CRC = (uint8_t)(Sum % 31);
|
||||
|
||||
/* Return the CRC */
|
||||
return CRC;
|
||||
} /* End ComputeCrc5Bit() */
|
||||
|
||||
uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength)
|
||||
{
|
||||
uint32_t Output = 0;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < BitLength; i++)
|
||||
{
|
||||
Output <<= 1;
|
||||
Output |= (uint32_t)(BufferIn[i] & 1);
|
||||
}
|
||||
|
||||
return Output;
|
||||
} /* End ConvertBitIntoBytes() */
|
||||
|
||||
/*
|
||||
* @brief : This function compute the CRC-9 of the DMR data
|
||||
* by using the polynomial x^9 + x^6 + x^4 + x^3 + 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 9 bit CRC
|
||||
*/
|
||||
660
src/dmr_voice.c
660
src/dmr_voice.c
@@ -1,660 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
|
||||
void processDMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// extracts AMBE frames from DMR frame
|
||||
int i, j, k, l, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
char cachdata[13] = {0};
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
char cc[4];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
unsigned int EmbeddedSignallingOk;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
int k;
|
||||
char syncbits[49];
|
||||
char cachbits[25];12
|
||||
#endif
|
||||
|
||||
/* Init the superframe buffers */
|
||||
memset(&state->TS1SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t));
|
||||
memset(&state->TS2SuperFrame, 0, sizeof(TimeSlotVoiceSuperFrame_t));
|
||||
|
||||
/* Init the color code status */
|
||||
state->color_code_ok = 0;
|
||||
|
||||
mutecurrentslot = 0;
|
||||
msMode = 0;
|
||||
|
||||
dibit_p = state->dibit_buf_p - 144;
|
||||
for(j = 0; j < 6; j++)
|
||||
{
|
||||
// 2nd half of previous slot
|
||||
for(i = 0; i < 54; i++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CACH
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
cachdata[i] = dibit;
|
||||
if(i == 2)
|
||||
{
|
||||
/* Change the current slot only if we are in relayed mode (not in direct mode) */
|
||||
if(state->directmode == 0) state->currentslot = (1 & (dibit >> 1)); // bit 1
|
||||
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
state->slot1light[0] = '[';
|
||||
state->slot1light[6] = ']';
|
||||
state->slot2light[0] = ' ';
|
||||
state->slot2light[6] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
state->slot2light[0] = '[';
|
||||
state->slot2light[6] = ']';
|
||||
state->slot1light[0] = ' ';
|
||||
state->slot1light[6] = ' ';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
cachdata[12] = 0;
|
||||
|
||||
//set state-dmrburstL and R here to a value for ncurses
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->dmrburstL = 16; //use 16 for Voice?
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
state->dmrburstR = 16; //Use 16 for Voice?
|
||||
}
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
fprintf(stderr, "%s ", cachbits);
|
||||
#endif
|
||||
|
||||
// current slot frame 1
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
k = 0;
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
/* Save the current frame in the appropriate superframe buffer */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => RAW voice bit */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => RAW voice bit */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[0][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[0][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
// current slot frame 2 first half
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
k = 0;
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
/* Save the current frame in the appropriate superframe buffer */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => RAW voice bit */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => RAW voice bit */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
l = 0;
|
||||
// signaling data or sync
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
|
||||
/* Save the current frame in the appropriate superframe buffer */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => SYNC data */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => SYNC data */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].Sync[l++] = (1 & dibit); // bit 0
|
||||
}
|
||||
}
|
||||
sync[24] = 0;
|
||||
|
||||
/* Copy the Embedded signaling (1st part) */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
EmbeddedSignalling[i] = syncdata[i];
|
||||
}
|
||||
/* Copy the Embedded signaling (2nd part) */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
||||
}
|
||||
|
||||
/* Check and correct the SlotType (apply Golay(20,8) FEC check) */
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling)) EmbeddedSignallingOk = 1;
|
||||
else EmbeddedSignallingOk = 0;
|
||||
|
||||
/* Get the color code */
|
||||
cc[0] = EmbeddedSignalling[0];
|
||||
cc[1] = EmbeddedSignalling[1];
|
||||
cc[2] = EmbeddedSignalling[2];
|
||||
cc[3] = EmbeddedSignalling[3];
|
||||
|
||||
/* The color code is normally the same for all
|
||||
* 6 received voice frame, so in case of error
|
||||
* do not store it except if the last SYNC frame
|
||||
* has been received. */
|
||||
if(EmbeddedSignallingOk || ((state->color_code_ok == 0) && (j == 5)))
|
||||
{
|
||||
/* Save the color code */
|
||||
state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]);
|
||||
state->color_code_ok = EmbeddedSignallingOk;
|
||||
}
|
||||
|
||||
/* Save the Power Control (PI) indicator */
|
||||
state->PI = (unsigned int)EmbeddedSignalling[4];
|
||||
state->PI_ok = EmbeddedSignallingOk;
|
||||
|
||||
/* Save the Link Control Start Stop (LCSS) indicator */
|
||||
state->LCSS = (unsigned int)((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
state->LCSS_ok = EmbeddedSignallingOk;
|
||||
|
||||
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
mutecurrentslot = 1;
|
||||
state->directmode = 0;
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
}
|
||||
}
|
||||
else if(strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)
|
||||
{
|
||||
mutecurrentslot = 1;
|
||||
state->currentslot = 0;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot1light, "[sLoT1]");
|
||||
}
|
||||
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
|
||||
{
|
||||
mutecurrentslot = 1;
|
||||
state->currentslot = 1;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot1light, "[sLoT2]");
|
||||
}
|
||||
else if((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) ) //|| (strcmp (sync, DMR_MS_VOICE_SYNC) == 0))
|
||||
{
|
||||
mutecurrentslot = 0;
|
||||
state->directmode = 0;
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
sprintf(state->slot1light, "[SLOT1]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->slot2light, "[SLOT2]");
|
||||
}
|
||||
}
|
||||
else if(strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0)
|
||||
{
|
||||
mutecurrentslot = 0;
|
||||
state->currentslot = 0;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot1light, "[sLoT1]");
|
||||
}
|
||||
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
|
||||
{
|
||||
mutecurrentslot = 0;
|
||||
state->currentslot = 1;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot2light, "[sLoT2]");
|
||||
}
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = syncdata[i];
|
||||
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
fprintf(stderr, "%s ", syncbits);
|
||||
#endif
|
||||
|
||||
// current slot frame 2 second half
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
/* Save the current frame in the appropriate superframe buffer */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => RAW voice bit */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[1][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[1][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
if(mutecurrentslot == 0)
|
||||
{
|
||||
if(state->firstframe == 1)
|
||||
{ // we don't know if anything received before the first sync after no carrier is valid
|
||||
state->firstframe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// current slot frame 3
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
k = 0;
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
/* Save the current frame in the appropriate superframe buffer */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* Time slot 1 superframe buffer filling => RAW voice bit */
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 1 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Time slot 2 superframe buffer filling => RAW voice bit */
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotRawVoiceFrame[j].VoiceFrame[2][k++] = (1 & dibit); // bit 0
|
||||
|
||||
/* Time slot 2 superframe buffer filling => Deinterleaved voice bit */
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[2][*y][*z] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
if(mutecurrentslot == 0)
|
||||
{
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
// CACH
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
cachdata[i] = dibit;
|
||||
}
|
||||
cachdata[12] = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
fprintf(stderr, "%s ", cachbits);
|
||||
#endif
|
||||
|
||||
|
||||
// next slot
|
||||
skipDibit (opts, state, 54);
|
||||
|
||||
// signaling data or sync
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
syncdata[i] = dibit;
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
syncdata[24] = 0;
|
||||
|
||||
if((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1))
|
||||
{
|
||||
state->directmode = 0;
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
}
|
||||
}
|
||||
else if(strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
|
||||
{
|
||||
state->directmode = 0;
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
sprintf(state->slot2light, " SLOT2 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(state->slot1light, " SLOT1 ");
|
||||
}
|
||||
}
|
||||
else if((strcmp (sync, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0))
|
||||
{
|
||||
state->currentslot = 0;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot1light, " sLoT1 ");
|
||||
}
|
||||
else if((strcmp (sync, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0) || (strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0))
|
||||
{
|
||||
state->currentslot = 1;
|
||||
state->directmode = 1; /* Direct mode */
|
||||
sprintf(state->slot1light, " sLoT2 ");
|
||||
}
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = syncdata[i];
|
||||
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
fprintf(stderr, "%s ", syncbits);
|
||||
#endif
|
||||
|
||||
if(j == 5) //j == 5
|
||||
{
|
||||
|
||||
// 2nd half next slot
|
||||
skipDibit (opts, state, 54);
|
||||
|
||||
// CACH
|
||||
skipDibit (opts, state, 12);
|
||||
|
||||
// first half current slot
|
||||
skipDibit (opts, state, 54);
|
||||
}
|
||||
|
||||
/* Extract the 49 bits AMBE of the voice frame */
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
/* 3 x 49 bit of AMBE sample per voice frame => Slot 1buffer here */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
|
||||
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
|
||||
|
||||
mbe_demodulateAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
|
||||
&(state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3 x 49 bit of AMBE sample per voice frame => Slot 2 buffer here */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
|
||||
|
||||
mbe_demodulateAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
|
||||
&(state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /* End for(j = 0; j < 6; j++) */
|
||||
|
||||
if(opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
|
||||
/* Print the color code */
|
||||
fprintf (stderr, "%s", KCYN);
|
||||
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
|
||||
//if(state->color_code_ok) fprintf(stderr, "(OK) |");
|
||||
if(state->color_code_ok)
|
||||
{
|
||||
fprintf(stderr, "| (CRC OK ) |"); //add line break
|
||||
state->dmr_color_code = state->color_code; //set here when voice? otherwise is set off of idle.
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf(stderr, "| (CRC ERR) |"); //add line break
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
|
||||
fprintf(stderr, " VOICE ");
|
||||
}
|
||||
|
||||
/* Perform the SYNC DMR data embedded decoding */
|
||||
ProcessVoiceBurstSync(opts, state);
|
||||
|
||||
/* Perform the DMR voice decoding */
|
||||
ProcessDMR(opts, state);
|
||||
|
||||
//LFSR if required, change condition?
|
||||
if ( (state->currentslot == 0 && state->payload_algid == 0x21 ) || //&& opts->payload == 1
|
||||
(state->currentslot == 1 && state->payload_algidR == 0x21 ) ) //&& opts->payload == 1
|
||||
{
|
||||
LFSR(state);
|
||||
}
|
||||
|
||||
if(opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
} /* End processDMRvoice() */
|
||||
140
src/dsd_file.c
140
src/dsd_file.c
@@ -166,7 +166,7 @@ PrintIMBEData (dsd_opts * opts, dsd_state * state, char *imbe_d) //for P25P1 and
|
||||
}
|
||||
|
||||
void
|
||||
PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stereo, may use this for NXDN too
|
||||
PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
@@ -174,7 +174,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere
|
||||
|
||||
err = (unsigned char) state->errs2;
|
||||
k = 0;
|
||||
if (opts->dmr_stereo == 0)
|
||||
if (opts->dmr_stereo == 0 && opts->dmr_mono == 0)
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
@@ -183,7 +183,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere
|
||||
fprintf(stderr, " AMBE ");
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
@@ -192,13 +192,13 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
|
||||
if (opts->payload == 1 && i < 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", b);
|
||||
}
|
||||
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit, value will be either 0x00 or 0x80?
|
||||
if (opts->payload == 1 && i == 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", b & 0x80); //7th octet should only contain 1 bit
|
||||
fprintf (stderr, "%02X", b & 0x80);
|
||||
}
|
||||
}
|
||||
if (state->currentslot == 0)
|
||||
@@ -207,7 +207,7 @@ PrintAMBEData (dsd_opts * opts, dsd_state * state, char *ambe_d) //For DMR Stere
|
||||
}
|
||||
else fprintf(stderr, " err = [%X] [%X] ", state->errsR, state->errs2R);
|
||||
b = ambe_d[48];
|
||||
if (opts->dmr_stereo == 1) //need to fix the printouts again
|
||||
if (opts->dmr_stereo == 1 || opts->dmr_mono == 1) //need to fix the printouts again
|
||||
{
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
@@ -226,7 +226,7 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
|
||||
|
||||
k = 0;
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@@ -248,12 +248,12 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
b = b & 255;
|
||||
k++;
|
||||
}
|
||||
//new printout on reading MBE files back in
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "%02X", x);
|
||||
}
|
||||
//
|
||||
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
@@ -273,11 +273,11 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
state->errs = state->errs2;
|
||||
|
||||
k = 0;
|
||||
if (opts->payload == 1) //make opt variable later on to toggle this
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
//for (i = 0; i < 6; i++)
|
||||
|
||||
for (i = 0; i < 6; i++) //breaks backwards compatablilty with 6 files
|
||||
{
|
||||
b = fgetc (opts->mbe_in_f);
|
||||
@@ -296,13 +296,13 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
b = b & 255;
|
||||
k++;
|
||||
}
|
||||
if (opts->payload == 1 && i < 6) //make opt variable later on to toggle this
|
||||
if (opts->payload == 1 && i < 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", x);
|
||||
}
|
||||
if (opts->payload == 1 && i == 6) //7th octet should only contain 1 bit? value will be either 0x00 or 0x80?
|
||||
if (opts->payload == 1 && i == 6)
|
||||
{
|
||||
fprintf (stderr, "%02X", x & 0x80); //7th octet should only contain 1 bit?
|
||||
fprintf (stderr, "%02X", x & 0x80);
|
||||
}
|
||||
}
|
||||
if (opts->payload == 1)
|
||||
@@ -349,82 +349,6 @@ openMbeInFile (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//temporarily disabled until the compiler warnings can be fixed, use symbol capture or per call instead!
|
||||
//probably the easiest thing is to just have this run fclose, and have name assignment on open instead.
|
||||
// void
|
||||
// closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
// {
|
||||
//
|
||||
// char shell[255], newfilename[64], ext[5], datestr[32], new_path[1024];
|
||||
// char tgid[17];
|
||||
// int sum, i, j;
|
||||
// int talkgroup;
|
||||
// struct tm timep;
|
||||
// int result;
|
||||
//
|
||||
// if (opts->mbe_out_f != NULL)
|
||||
// {
|
||||
// if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
|
||||
// {
|
||||
// sprintf (ext, ".imb");
|
||||
// //strptime (opts->mbe_out_file, "%s.imb", &timep);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sprintf (ext, ".amb");
|
||||
// //strptime (opts->mbe_out_file, "%s.amb", &timep);
|
||||
// }
|
||||
//
|
||||
// if (state->tgcount > 0)
|
||||
// {
|
||||
// for (i = 0; i < 16; i++)
|
||||
// {
|
||||
// sum = 0;
|
||||
// for (j = 0; j < state->tgcount; j++)
|
||||
// {
|
||||
// sum = sum + state->tg[j][i] - 48;
|
||||
// }
|
||||
// tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5);
|
||||
// }
|
||||
// tgid[16] = 0;
|
||||
// talkgroup = (int) strtol (tgid, NULL, 2);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// talkgroup = 0;
|
||||
// }
|
||||
//
|
||||
// fflush (opts->mbe_out_f);
|
||||
// fclose (opts->mbe_out_f);
|
||||
// opts->mbe_out_f = NULL;
|
||||
// strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep);
|
||||
//
|
||||
// sprintf (newfilename, "%s%s", datestr, ext); //this one
|
||||
//
|
||||
// if (state->lastsynctype == 0 || state->lastsynctype == 1)
|
||||
// {
|
||||
// sprintf (newfilename, "%s-nac%X-tg%i%s", datestr, state->nac, talkgroup, ext);
|
||||
// }
|
||||
//
|
||||
// //sprintf (new_path, "%s%s", opts->mbe_out_dir, newfilename);
|
||||
// #ifdef _WIN32
|
||||
// //sprintf (shell, "move %s %s", opts->mbe_out_path, new_path);
|
||||
// #else
|
||||
// //sprintf (shell, "mv %s %s", opts->mbe_out_path, new_path);
|
||||
// #endif
|
||||
// //result = system (shell);
|
||||
//
|
||||
// state->tgcount = 0;
|
||||
// for (i = 0; i < 25; i++)
|
||||
// {
|
||||
// for (j = 0; j < 16; j++)
|
||||
// {
|
||||
// state->tg[i][j] = 48;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//much simpler version
|
||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
@@ -447,7 +371,6 @@ void
|
||||
openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
//struct timeval tv;
|
||||
int i, j;
|
||||
char ext[5];
|
||||
|
||||
@@ -471,10 +394,6 @@ openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
//gettimeofday (&tv, NULL);
|
||||
//rewrite below line to take getTime function instead?
|
||||
// sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext);
|
||||
|
||||
sprintf (opts->mbe_out_file, "%s %s%s", getDateF(), getTimeF(), ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
||||
@@ -500,7 +419,6 @@ openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
info.samplerate = 8000; //8000
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
|
||||
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
|
||||
|
||||
if (opts->wav_out_f == NULL)
|
||||
@@ -508,18 +426,15 @@ openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
|
||||
return;
|
||||
}
|
||||
|
||||
// state->wav_out_bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
void openWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
SF_INFO info;
|
||||
info.samplerate = 8000; //8000
|
||||
info.samplerate = 8000;
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
|
||||
opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
|
||||
|
||||
if (opts->wav_out_f == NULL)
|
||||
@@ -527,9 +442,6 @@ void openWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_file);
|
||||
return;
|
||||
}
|
||||
|
||||
// state->wav_out_bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
@@ -539,7 +451,6 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
info.samplerate = 8000; //8000
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
|
||||
opts->wav_out_fR = sf_open (opts->wav_out_fileR, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
|
||||
|
||||
if (opts->wav_out_f == NULL)
|
||||
@@ -547,9 +458,6 @@ void openWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"Error - could not open wav output file %s\n", opts->wav_out_fileR);
|
||||
return;
|
||||
}
|
||||
|
||||
// state->wav_out_bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||
@@ -559,17 +467,12 @@ void openWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||
info.samplerate = 48000; //8000
|
||||
info.channels = 1;
|
||||
info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
|
||||
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_WRITE, &info);
|
||||
//opts->wav_out_f = sf_open (opts->wav_out_file, SFM_RDWR, &info); //RDWR will append to file instead of overwrite file
|
||||
opts->wav_out_raw = sf_open (opts->wav_out_file_raw, SFM_RDWR, &info);
|
||||
if (opts->wav_out_raw == NULL)
|
||||
{
|
||||
fprintf (stderr,"Error - could not open raw wav output file %s\n", opts->wav_out_file_raw);
|
||||
return;
|
||||
}
|
||||
|
||||
// state->wav_out_bytes = 0;
|
||||
|
||||
}
|
||||
|
||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
@@ -609,15 +512,12 @@ void closeSymbolOutFile (dsd_opts * opts, dsd_state * state)
|
||||
//Do something
|
||||
if (opts->symbol_out == 1)
|
||||
{
|
||||
if (opts->symbol_out_file != NULL) //check first, or issuing a second fclose will crash the SOFTWARE
|
||||
if (opts->symbol_out_file != NULL)
|
||||
{
|
||||
fclose(opts->symbol_out_f); //free(): double free detected in tcache 2 (this is a new one) happens when closing more than once
|
||||
//noCarrier(opts, state); //free(): double free detected in tcache 2 (this is a new one)
|
||||
fclose(opts->symbol_out_f);
|
||||
}
|
||||
|
||||
opts->symbol_out = 0; //set flag to 1
|
||||
//sprintf (opts->symbol_out_file, "fme-capture.bin"); //use fme for the symbol bin ext
|
||||
//openSymbolOutFile (opts, state);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -163,13 +163,14 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
processDMRvoice (opts, state);
|
||||
dmrMSBootstrap (opts, state);
|
||||
}
|
||||
if (opts->dmr_stereo == 0 && state->synctype == 32)
|
||||
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);
|
||||
// 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
|
||||
{
|
||||
@@ -183,19 +184,20 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else if ( (state->synctype == 33) || (state->synctype == 34) ) //MS Data and RC data
|
||||
{
|
||||
if (opts->dmr_stereo == 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (opts->dmr_stereo == 1)
|
||||
{
|
||||
dmrMSData (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
|
||||
{
|
||||
@@ -206,7 +208,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
state->payload_miP = 0; //zero out when switching back to data sync
|
||||
processDMRdata (opts, state);
|
||||
dmr_data_sync (opts, state);
|
||||
}
|
||||
//switch dmr_stereo to 0 when handling BS data frame syncs with processDMRdata
|
||||
if (opts->dmr_stereo == 1)
|
||||
@@ -215,7 +217,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
state->payload_miP = 0; //zero out when switching back to data sync
|
||||
processDMRdata (opts, state);
|
||||
dmr_data_sync (opts, state);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -889,7 +889,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 11)
|
||||
{
|
||||
@@ -1003,7 +1003,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 12)
|
||||
{
|
||||
|
||||
198
src/dsd_main.c
198
src/dsd_main.c
@@ -201,6 +201,8 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->HYTR = 0;
|
||||
state->DMRvcL = 0;
|
||||
state->DMRvcR = 0;
|
||||
state->dropL = 256;
|
||||
state->dropR = 256;
|
||||
|
||||
state->payload_miN = 0;
|
||||
state->p25vc = 0;
|
||||
@@ -210,19 +212,6 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_lrrp_source[0] = 0;
|
||||
state->dmr_lrrp_source[1] = 0;
|
||||
|
||||
//initialize 12 rate superframe
|
||||
for (short i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_12_rate_sf[0][i] = 0;
|
||||
state->dmr_12_rate_sf[1][i] = 0;
|
||||
}
|
||||
|
||||
//initialize 34 rate superframe
|
||||
for (short i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_34_rate_sf[0][i] = 0;
|
||||
state->dmr_34_rate_sf[1][i] = 0;
|
||||
}
|
||||
|
||||
//initialize data header bits
|
||||
state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header
|
||||
@@ -268,7 +257,29 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment));
|
||||
sprintf (state->nxdn_call_type, "%s", "");
|
||||
|
||||
}
|
||||
state->dmr_rest_channel = -1; //init on -1
|
||||
sprintf(state->dmr_branding_sub, "%s", "");
|
||||
sprintf(state->dmr_branding, "%s", "");
|
||||
state->dmr_mfid = 0;
|
||||
|
||||
//dmr slco stuff
|
||||
memset(state->dmr_cach_fragment, 0, sizeof(state->dmr_cach_fragment));
|
||||
state->dmr_cach_counter = 0;
|
||||
|
||||
//initialize unified dmr pdu 'superframe'
|
||||
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
|
||||
//embedded signalling
|
||||
memset(state->dmr_embedded_signalling, 0, sizeof(state->dmr_embedded_signalling));
|
||||
|
||||
//late entry mi fragments
|
||||
memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment));
|
||||
|
||||
|
||||
} //nocarrier
|
||||
|
||||
void
|
||||
initOpts (dsd_opts * opts)
|
||||
@@ -376,6 +387,7 @@ initOpts (dsd_opts * opts)
|
||||
opts->ncurses_history = 1;
|
||||
opts->payload = 0;
|
||||
opts->inverted_dpmr = 0;
|
||||
opts->dmr_mono = 0;
|
||||
opts->dmr_stereo = 1;
|
||||
opts->aggressive_framesync = 1; //more aggressive to combat wonk wonk voice decoding
|
||||
//see if initializing these values causes issues elsewhere, if so, then disable.
|
||||
@@ -414,7 +426,7 @@ initOpts (dsd_opts * opts)
|
||||
opts->p25_is_tuned = 0; //set to 1 if currently on VC, set back to 0 on carrier drop
|
||||
opts->trunk_hangtime = 1; //1 second hangtime by default before tuning back to CC
|
||||
|
||||
}
|
||||
} //initopts
|
||||
|
||||
void
|
||||
initState (dsd_state * state)
|
||||
@@ -569,7 +581,6 @@ initState (dsd_state * state)
|
||||
state->fourv_counter[0] = 0;
|
||||
state->fourv_counter[1] = 0;
|
||||
|
||||
sprintf (state->dmr_branding, "%s", "");
|
||||
sprintf (state->dmr_callsign[0][0], "%s", "");
|
||||
sprintf (state->dmr_callsign[0][1], "%s", "");
|
||||
sprintf (state->dmr_callsign[0][2], "%s", "");
|
||||
@@ -618,6 +629,8 @@ initState (dsd_state * state)
|
||||
state->HYTR = 0;
|
||||
state->DMRvcL = 0;
|
||||
state->DMRvcR = 0;
|
||||
state->dropL = 256;
|
||||
state->dropR = 256;
|
||||
|
||||
state->p25vc = 0;
|
||||
|
||||
@@ -629,19 +642,6 @@ initState (dsd_state * state)
|
||||
state->dmr_lrrp_source[0] = 0;
|
||||
state->dmr_lrrp_source[1] = 0;
|
||||
|
||||
//initialize 12 rate superframe
|
||||
for (short i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_12_rate_sf[0][i] = 0;
|
||||
state->dmr_12_rate_sf[1][i] = 0;
|
||||
}
|
||||
|
||||
//initialize 34 rate superframe
|
||||
for (short i = 0; i < 288; i++)
|
||||
{
|
||||
state->dmr_34_rate_sf[0][i] = 0;
|
||||
state->dmr_34_rate_sf[1][i] = 0;
|
||||
}
|
||||
|
||||
//initialize data header bits
|
||||
state->data_header_blocks[0] = 1; //initialize with 1, otherwise we may end up segfaulting when no/bad data header
|
||||
@@ -735,6 +735,30 @@ initState (dsd_state * state)
|
||||
state->dmr_end_alert[0] = 0;
|
||||
state->dmr_end_alert[1] = 0;
|
||||
|
||||
sprintf (state->dmr_branding, "%s", "");
|
||||
sprintf (state->dmr_branding_sub, "%s", "");
|
||||
|
||||
//initialize unified dmr pdu 'superframe'
|
||||
memset (state->dmr_pdu_sf, 0, sizeof (state->dmr_pdu_sf));
|
||||
|
||||
//init confirmed data individual block crc as invalid
|
||||
memset (state->data_block_crc_valid, 0, sizeof(state->data_block_crc_valid));
|
||||
|
||||
//dmr slco stuff
|
||||
memset(state->dmr_cach_fragment, 0, sizeof(state->dmr_cach_fragment));
|
||||
state->dmr_cach_counter = 0;
|
||||
|
||||
//embedded signalling
|
||||
memset(state->dmr_embedded_signalling, 0, sizeof(state->dmr_embedded_signalling));
|
||||
|
||||
//dmr talker alias new/fixed stuff
|
||||
memset(state->dmr_alias_format, 0, sizeof(state->dmr_alias_format));
|
||||
memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len));
|
||||
memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
|
||||
|
||||
//late entry mi fragments
|
||||
memset (state->late_entry_mi_fragment, 0, sizeof (state->late_entry_mi_fragment));
|
||||
|
||||
initialize_p25_heuristics(&state->p25_heuristics);
|
||||
}
|
||||
|
||||
@@ -805,7 +829,7 @@ usage ()
|
||||
printf (" -fs DMR Stereo BS and MS Simplex only\n");
|
||||
printf (" -f1 Decode only P25 Phase 1\n");
|
||||
printf (" -fd Decode only D-STAR\n");
|
||||
printf (" -fr Decode only DMR (LEH)\n");
|
||||
printf (" -fr Decode only DMR Mono - Single Slot Voice\n");
|
||||
printf (" -fx Decode only X2-TDMA\n");
|
||||
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
|
||||
printf (" -fn Decode only NXDN96* (12.5 kHz)\n");
|
||||
@@ -860,7 +884,7 @@ usage ()
|
||||
printf (" (See channel_map.csv for example)\n");
|
||||
printf (" -2 <file> Import Group List Allow/Block and Label from csv file (numeral 'two')\n");
|
||||
printf (" (See group.csv for example)\n");
|
||||
printf (" -3 Enable Extremely Experimental Trunking Features (NXDN/P25/EDACS for now) with RIGCTL/TCP or RTL Input\n");
|
||||
printf (" -3 Enable Extremely Experimental Trunking Features (NXDN/P25/EDACS/DMR TIII, Con+) with RIGCTL/TCP or RTL Input\n");
|
||||
printf (" -5 <udp p> Enable RIGCTL/TCP; Set UDP Port for RIGCTL. (4532 on SDR++)\n");
|
||||
printf (" -6 <secs> Set Trunking VC/sync loss hangtime in seconds. (default = 1 second)\n");
|
||||
//printf (" (Currently only available on UDP port 4532)\n");
|
||||
@@ -1000,29 +1024,6 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"Total audio errors: %i\n", state->debug_audio_errors);
|
||||
fprintf (stderr,"Total header errors: %i\n", state->debug_header_errors);
|
||||
fprintf (stderr,"Total irrecoverable header errors: %i\n", state->debug_header_critical_errors);
|
||||
|
||||
//debug_print_heuristics(&(state->p25_heuristics));
|
||||
|
||||
fprintf (stderr,"\n");
|
||||
fprintf (stderr,"+P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->p25_heuristics));
|
||||
fprintf (stderr,"-P25 BER estimate: %.2f%%\n", get_P25_BER_estimate(&state->inv_p25_heuristics));
|
||||
fprintf (stderr,"\n");
|
||||
|
||||
#ifdef TRACE_DSD
|
||||
if (state->debug_label_file != NULL) {
|
||||
fclose(state->debug_label_file);
|
||||
state->debug_label_file = NULL;
|
||||
}
|
||||
if(state->debug_label_dibit_file != NULL) {
|
||||
fclose(state->debug_label_dibit_file);
|
||||
state->debug_label_dibit_file = NULL;
|
||||
}
|
||||
if(state->debug_label_imbe_file != NULL) {
|
||||
fclose(state->debug_label_imbe_file);
|
||||
state->debug_label_imbe_file = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf (stderr,"Exiting.\n");
|
||||
exit (0);
|
||||
}
|
||||
@@ -1103,10 +1104,9 @@ main (int argc, char **argv)
|
||||
usage ();
|
||||
exit (0);
|
||||
case 'a':
|
||||
//printPortAudioDevices();
|
||||
//exit(0);
|
||||
opts.call_alert = 1;
|
||||
break;
|
||||
|
||||
//placeholder until letters get re-arranged (or opt_long switched in)
|
||||
case '1': //LCN to Frequency CSV Import
|
||||
strncpy(opts.lcn_in_file, optarg, 1023);
|
||||
@@ -1169,7 +1169,6 @@ main (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
//can't handle negative numbers?
|
||||
sscanf (optarg, "%d", &opts.rtlsdr_ppm_error);
|
||||
break;
|
||||
case 'q':
|
||||
@@ -1177,18 +1176,10 @@ main (int argc, char **argv)
|
||||
opts.verbose = 0;
|
||||
break;
|
||||
case 's':
|
||||
// opts.errorbars = 0;
|
||||
// opts.p25enc = 0;
|
||||
// opts.p25lc = 0;
|
||||
// opts.p25status = 0;
|
||||
// opts.p25tg = 0;
|
||||
// opts.datascope = 1;
|
||||
// opts.symboltiming = 0;
|
||||
sscanf (optarg, "%d", &opts.wav_sample_rate);
|
||||
opts.wav_interpolator = opts.wav_sample_rate / opts.wav_decimator;
|
||||
state.samplesPerSymbol = state.samplesPerSymbol * opts.wav_interpolator;
|
||||
state.symbolCenter = state.symbolCenter * opts.wav_interpolator;
|
||||
//fprintf (stderr, "Are we getting this far?\n");
|
||||
break;
|
||||
case 't':
|
||||
opts.symboltiming = 1;
|
||||
@@ -1249,21 +1240,6 @@ main (int argc, char **argv)
|
||||
opts.dmr_mute_encR = 1;
|
||||
}
|
||||
state.H = state.K1; //shim still required?
|
||||
|
||||
//old handling for 10 Char Key
|
||||
// sscanf (optarg, "%llX", &state.H);
|
||||
// if (state.H > 0xFFFFFFFFFF)
|
||||
// {
|
||||
// state.H = 0xFFFFFFFFFF;
|
||||
// }
|
||||
// opts.dmr_mute_encL = 0;
|
||||
// opts.dmr_mute_encR = 0;
|
||||
// if (state.H == 0)
|
||||
// {
|
||||
// opts.dmr_mute_encL = 1;
|
||||
// opts.dmr_mute_encR = 1;
|
||||
// }
|
||||
// state.K1 = state.H; //shim
|
||||
break;
|
||||
|
||||
case '4':
|
||||
@@ -1423,11 +1399,6 @@ main (int argc, char **argv)
|
||||
opts.serial_dev[1023] = '\0';
|
||||
break;
|
||||
|
||||
// case 'R':
|
||||
// sscanf (optarg, "%d", &opts.resume);
|
||||
// fprintf (stderr,"Enabling scan resume after %i TDULC frames\n", opts.resume);
|
||||
// break;
|
||||
|
||||
case 'f':
|
||||
if (optarg[0] == 'a')
|
||||
{
|
||||
@@ -1444,6 +1415,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 1;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "Legacy Auto");
|
||||
}
|
||||
@@ -1463,6 +1435,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.rf_mod = 0;
|
||||
sprintf (opts.output_name, "D-STAR");
|
||||
fprintf (stderr,"Decoding only D-STAR frames.\n");
|
||||
@@ -1482,6 +1455,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "X2-TDMA");
|
||||
fprintf (stderr,"Decoding only X2-TDMA frames.\n");
|
||||
@@ -1507,6 +1481,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "EDACS/PV");
|
||||
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
||||
@@ -1530,6 +1505,8 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 0; //
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
sprintf (opts.output_name, "P25P1");
|
||||
@@ -1557,6 +1534,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
sprintf (opts.output_name, "NXDN48");
|
||||
fprintf (stderr,"Setting symbol rate to 2400 / second\n");
|
||||
fprintf (stderr,"Decoding only NXDN 4800 baud frames.\n");
|
||||
@@ -1584,6 +1562,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
sprintf (opts.output_name, "YSF");
|
||||
fprintf (stderr,"Setting symbol rate to 2400 / second\n");
|
||||
fprintf (stderr,"Decoding only YSF frames.\nNot working yet!\n");
|
||||
@@ -1608,6 +1587,7 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
state.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
sprintf (opts.output_name, "P25P2");
|
||||
fprintf (stderr,"Decoding P25-P2 frames C4FM or OP25 Symbol Captures!\n");
|
||||
}
|
||||
@@ -1629,7 +1609,7 @@ main (int argc, char **argv)
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
//state.dmr_stereo = 1; //manually set to 1
|
||||
opts.dmr_mono = 0;
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "DMR Stereo");
|
||||
@@ -1655,7 +1635,7 @@ main (int argc, char **argv)
|
||||
//or consider using an external modulator (GNURadio?)
|
||||
state.rf_mod = 0;
|
||||
opts.dmr_stereo = 1;
|
||||
//state.dmr_stereo = 1;
|
||||
opts.dmr_mono = 0;
|
||||
opts.pulse_digi_rate_out = 24000;
|
||||
opts.pulse_digi_out_channels = 2;
|
||||
sprintf (opts.output_name, "XDMA");
|
||||
@@ -1680,6 +1660,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "NXDN96");
|
||||
fprintf (stderr,"Decoding only NXDN 9600 baud frames.\n");
|
||||
@@ -1702,11 +1683,34 @@ main (int argc, char **argv)
|
||||
state.rf_mod = 0; //
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_mono = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "DMR LEH");
|
||||
fprintf(stderr, "Notice: DMR cannot autodetect polarity. \n Use -xr option if Inverted Signal expected.\n");
|
||||
fprintf (stderr,"Decoding only DMR frames.\n");
|
||||
state.dmr_stereo = 0; //0
|
||||
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");
|
||||
//dmr stereo below
|
||||
// opts.frame_dstar = 0;
|
||||
// opts.frame_x2tdma = 0;
|
||||
// opts.frame_p25p1 = 0;
|
||||
// opts.frame_p25p2 = 0;
|
||||
// opts.inverted_p2 = 0;
|
||||
// opts.frame_nxdn48 = 0;
|
||||
// opts.frame_nxdn96 = 0;
|
||||
// opts.frame_dmr = 1;
|
||||
// opts.frame_dpmr = 0;
|
||||
// opts.frame_provoice = 0;
|
||||
// opts.frame_ysf = 0;
|
||||
// opts.mod_c4fm = 1;
|
||||
// opts.mod_qpsk = 0;
|
||||
// opts.mod_gfsk = 0;
|
||||
// state.rf_mod = 0;
|
||||
// opts.dmr_stereo = 1;
|
||||
// state.dmr_stereo = 0;
|
||||
// opts.pulse_digi_rate_out = 24000;
|
||||
// opts.pulse_digi_out_channels = 2;
|
||||
// sprintf (opts.output_name, "DMR Stereo");
|
||||
// fprintf (stderr,"Decoding DMR Stereo BS/MS Simplex\n");
|
||||
}
|
||||
else if (optarg[0] == 'm')
|
||||
{
|
||||
@@ -1729,6 +1733,7 @@ main (int argc, char **argv)
|
||||
opts.pulse_digi_rate_out = 8000;
|
||||
opts.pulse_digi_out_channels = 1;
|
||||
opts.dmr_stereo = 0;
|
||||
opts.dmr_mono = 0;
|
||||
state.dmr_stereo = 0;
|
||||
sprintf (opts.output_name, "dPMR");
|
||||
fprintf(stderr, "Notice: dPMR cannot autodetect polarity. \n Use -xd option if Inverted Signal expected.\n");
|
||||
@@ -1739,10 +1744,11 @@ main (int argc, char **argv)
|
||||
case 'm':
|
||||
if (optarg[0] == 'a')
|
||||
{
|
||||
opts.mod_c4fm = 1;
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 0;
|
||||
// opts.mod_c4fm = 1;
|
||||
// opts.mod_qpsk = 1;
|
||||
// opts.mod_gfsk = 1;
|
||||
// state.rf_mod = 0;
|
||||
fprintf (stderr,"Don't use the -ma switch.\n");
|
||||
}
|
||||
else if (optarg[0] == 'c')
|
||||
{
|
||||
@@ -1927,8 +1933,6 @@ main (int argc, char **argv)
|
||||
opts.audio_out_type = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if((strncmp(opts.audio_in_dev, "pulse", 5) == 0))
|
||||
{
|
||||
opts.audio_in_type = 0;
|
||||
|
||||
@@ -245,7 +245,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
else
|
||||
{
|
||||
//stereo slots and slot 0 (left slot)
|
||||
if (state->currentslot == 0 && opts->dmr_stereo == 1)
|
||||
if (state->currentslot == 0) //&& opts->dmr_stereo == 1
|
||||
{
|
||||
|
||||
state->errs = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
@@ -340,7 +340,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
//stereo slots and slot 1 (right slot)
|
||||
if (state->currentslot == 1 && opts->dmr_stereo == 1)
|
||||
if (state->currentslot == 1) //&& opts->dmr_stereo == 1
|
||||
{
|
||||
|
||||
state->errsR = mbe_eccAmbe3600x2450C0 (ambe_fr);
|
||||
@@ -435,19 +435,19 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
//X2-TDMA? Not sure what still makes it this far to run under Framef
|
||||
if (opts->dmr_stereo == 0)
|
||||
{
|
||||
mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
PrintAMBEData (opts, state, ambe_d);
|
||||
}
|
||||
//only save MBE files if not enc or unmuted, THIS does not seem to work for some reason
|
||||
if (opts->mbe_out_f != NULL && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
|
||||
{
|
||||
saveAmbe2450Data (opts, state, ambe_d);
|
||||
}
|
||||
}
|
||||
// if (opts->dmr_stereo == 0)
|
||||
// {
|
||||
// mbe_processAmbe3600x2450Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
// if (opts->payload == 1)
|
||||
// {
|
||||
// PrintAMBEData (opts, state, ambe_d);
|
||||
// }
|
||||
// //only save MBE files if not enc or unmuted, THIS does not seem to work for some reason
|
||||
// if (opts->mbe_out_f != NULL && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
|
||||
// {
|
||||
// saveAmbe2450Data (opts, state, ambe_d);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -456,7 +456,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
int enc_bit = 0;
|
||||
//end enc check
|
||||
|
||||
if (opts->dmr_stereo == 1 && state->currentslot == 0)
|
||||
if ( (opts->dmr_mono == 1 ||opts->dmr_stereo == 1) && state->currentslot == 0) //all mono traffic routed through 'left'
|
||||
{
|
||||
enc_bit = (state->dmr_so >> 6) & 0x1;
|
||||
if (enc_bit == 1)
|
||||
@@ -494,7 +494,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->dmr_stereo == 1 && state->currentslot == 1)
|
||||
if (opts->dmr_stereo == 1 && state->currentslot == 1)
|
||||
{
|
||||
enc_bit = (state->dmr_soR >> 6) & 0x1;
|
||||
if (enc_bit == 0x1)
|
||||
@@ -533,7 +533,7 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
}
|
||||
|
||||
//if using anything but DMR Stereo, borrowing state->dmr_encL to signal enc or clear for other types
|
||||
if (opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
|
||||
if (opts->dmr_mono == 0 && opts->dmr_stereo == 0 && (opts->unmute_encrypted_p25 == 1 || state->dmr_encL == 0) )
|
||||
{
|
||||
state->debug_audio_errors += state->errs2;
|
||||
if (opts->audio_out == 1)
|
||||
|
||||
Reference in New Issue
Block a user