Staging for DMR Improvements

Staging for DMR Improvements
This commit is contained in:
lwvmobile
2022-03-06 18:30:29 -05:00
committed by GitHub
parent 2b71652b23
commit 5834914e91
17 changed files with 8149 additions and 501 deletions

76
include/dpmr_const.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* 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.
*/
//#ifdef __cplusplus
//extern "C" {
//#endif
#ifndef _MAIN
extern const int dPmrW[36];
extern const int dPmrX[36];
extern const int dPmrY[36];
extern const int dPmrZ[36];
//#else
/*
* dPMR AMBE interleave schedule
*/
// bit 1
const int dPmrW[36] = {
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2,
0, 2, 0, 2, 0, 2
};
const int dPmrX[36] = {
23, 10, 22, 9, 21, 8,
20, 7, 19, 6, 18, 5,
17, 4, 16, 3, 15, 2,
14, 1, 13, 0, 12, 10,
11, 9, 10, 8, 9, 7,
8, 6, 7, 5, 6, 4
};
// bit 0
const int dPmrY[36] = {
0, 2, 0, 2, 0, 2,
0, 2, 0, 3, 0, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3
};
const int dPmrZ[36] = {
5, 3, 4, 2, 3, 1,
2, 0, 1, 13, 0, 12,
22, 11, 21, 10, 20, 9,
19, 8, 18, 7, 17, 6,
16, 5, 15, 4, 14, 3,
13, 2, 12, 1, 11, 0
};
#endif
//#ifdef __cplusplus
//}
//#endif

View File

@@ -147,9 +147,116 @@ typedef struct
} NxdnElementsContent_t;
//LEH DMR
enum
{
MODE_UNENCRYPTED,
MODE_BASIC_PRIVACY,
MODE_ENHANCED_PRIVACY_ARC4,
MODE_ENHANCED_PRIVACY_AES256,
MODE_HYTERA_BASIC_40_BIT,
MODE_HYTERA_BASIC_128_BIT,
MODE_HYTERA_BASIC_256_BIT
};
//Read Solomon (12,9) constant
#define RS_12_9_DATASIZE 9
#define RS_12_9_CHECKSUMSIZE 3
//Read Solomon (12,9) struct
typedef struct
{
uint8_t data[RS_12_9_DATASIZE+RS_12_9_CHECKSUMSIZE];
} rs_12_9_codeword_t;
// Maximum degree of various polynomials.
#define RS_12_9_POLY_MAXDEG (RS_12_9_CHECKSUMSIZE*2)
typedef struct
{
uint8_t data[RS_12_9_POLY_MAXDEG];
} rs_12_9_poly_t;
#define RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND 0
#define RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED 1
#define RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CANT_BE_CORRECTED 2
typedef uint8_t rs_12_9_correct_errors_result_t;
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) */
}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;
//end borrow from LEH
//LEH dPMR
/* Could only be 2 or 4 */
#define NB_OF_DPMR_VOICE_FRAME_TO_DECODE 2
typedef struct
{
unsigned char RawVoiceBit[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][72];
unsigned int errs1[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4]; /* 8 x errors #1 computed when demodulate the AMBE voice bit of the frame */
unsigned int errs2[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4]; /* 8 x errors #2 computed when demodulate the AMBE voice bit of the frame */
unsigned char AmbeBit[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][49]; /* 8 x 49 bit of AMBE voice of the frame */
unsigned char CCHData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48];
unsigned int CCHDataHammingOk[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned char CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int CCHDataCrcOk[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned char CalledID[8];
unsigned int CalledIDOk;
unsigned char CallingID[8];
unsigned int CallingIDOk;
unsigned int FrameNumbering[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int CommunicationMode[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int Version[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int CommsFormat[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned char SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
unsigned int ColorCode[NB_OF_DPMR_VOICE_FRAME_TO_DECODE / 2];
} dPMRVoiceFS2Frame_t;
//
typedef struct
{
int onesymbol;
@@ -241,6 +348,15 @@ typedef struct
int reset_state;
int payload;
//LEH DMR Stuff
int EncryptionMode;
//LEH dPMR stuff
unsigned int dPMR_curr_frame_is_encrypted;
int dPMR_next_part_of_superframe;
int inverted_dpmr;
int frame_dpmr;
} dsd_opts;
typedef struct
@@ -295,7 +411,7 @@ typedef struct
int numtdulc;
int firstframe;
char slot0light[8];
char slot1light[8];
//char slot1light[8];
float aout_gain;
float aout_max_buf[200];
float *aout_max_buf_p;
@@ -356,9 +472,47 @@ typedef struct
char ambe_ciphered[49];
char ambe_deciphered[49];
//end borrow
//LEH DMR struff
unsigned int color_code;
unsigned int color_code_ok;
unsigned int PI;
unsigned int PI_ok;
unsigned int LCSS;
unsigned int LCSS_ok;
unsigned int dmr_fid;
unsigned int dmr_so;
char slot1light[8];
char slot2light[8];
int directmode;
TimeSlotVoiceSuperFrame_t TS1SuperFrame;
TimeSlotVoiceSuperFrame_t TS2SuperFrame;
//LEH dPMR stuff
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;
#ifdef TRACE_DSD
char debug_prefix;
@@ -421,11 +575,40 @@ typedef struct
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
//LEH dPMR
#define DPMR_FRAME_SYNC_1 "111333331133131131111313"
/* dPMR Frame Sync 2 - 24 bits sequence
* HEX : 5F F7 7D
* Binary : 0101 1111 1111 0111 0111 1101
* Dibit : 1 1 3 3 3 3 1 3 1 3 3 1 */
#define DPMR_FRAME_SYNC_2 "113333131331"
/* dPMR Frame Sync 3 - 24 bits sequence
* HEX : 7D DF F5
* Binary : 0111 1101 1101 1111 1111 0101
* Dibit : 1 3 3 1 3 1 3 3 3 3 1 1 */
#define DPMR_FRAME_SYNC_3 "133131333311"
/* dPMR Frame Sync 4 - 48 bits sequence
* HEX : FD 55 F5 DF 7F DD
* Binary : 1111 1101 0101 0101 1111 0101 1101 1111 0111 1111 1101 1101
* Dibit : 3 3 3 1 1 1 1 1 3 3 1 1 3 1 3 3 1 3 3 3 3 1 3 1 */
#define DPMR_FRAME_SYNC_4 "333111113311313313333131"
/* dPMR Frame Sync 1 to 4 - Inverted */
#define INV_DPMR_FRAME_SYNC_1 "333111113311313313333131"
#define INV_DPMR_FRAME_SYNC_2 "331111313113"
#define INV_DPMR_FRAME_SYNC_3 "311313111133"
#define INV_DPMR_FRAME_SYNC_4 "111333331133131131111313"
//
/*
* function prototypes
*/
void processDMRdata (dsd_opts * opts, dsd_state * state);
void processDMRvoice (dsd_opts * opts, dsd_state * state);
void processdPMRvoice (dsd_opts * opts, dsd_state * state);
void processAudio (dsd_opts * opts, dsd_state * state);
void playRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE
void openPulseInput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet
@@ -538,6 +721,83 @@ void ScrambledNXDNVoiceBit(int * LfsrValue, char * BufferIn, char * BufferOut, i
void NxdnEncryptionStreamGeneration (dsd_opts* opts, dsd_state* state, uint8_t KeyStream[1664]);
void processMbeFrameEncrypted (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24], char ambe_keystream[49], char imbe_keystream[88]);
//LEH dPMR
void dPMRVoiceFrameProcess(dsd_opts * opts, dsd_state * state);
void printdPMRAmbeVoiceSample(dsd_opts * opts, dsd_state * state);
void printdPMRRawVoiceFrame (dsd_opts * opts, dsd_state * state);
//dPMR functions
void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferOut, uint32_t NbOfBitToScramble);
void DeInterleave6x12DPmrBit(uint8_t * BufferIn, uint8_t * BufferOut);
uint8_t CRC7BitdPMR(uint8_t * BufferIn, uint32_t BitLength);
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]);
//LEH DMR
void ProcessDMREncryption (dsd_opts * opts, dsd_state * state); //consider if this is needed
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]);
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77]);
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32]);
//Read Solomon (12,9) functions
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome);
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);
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 Hamming_7_4_init();
void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_7_4_decode(unsigned char *rxBits);
void Hamming_12_8_init();
void Hamming_12_8_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_12_8_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
void Hamming_13_9_init();
void Hamming_13_9_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_13_9_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
void Hamming_15_11_init();
void Hamming_15_11_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_15_11_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
void Hamming_16_11_4_init();
void Hamming_16_11_4_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
void Golay_20_8_init();
void Golay_20_8_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Golay_20_8_decode(unsigned char *rxBits);
void Golay_23_12_init();
void Golay_23_12_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Golay_23_12_decode(unsigned char *rxBits);
void Golay_24_12_init();
void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits);
bool Golay_24_12_decode(unsigned char *rxBits);
void QR_16_7_6_init();
void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits);
bool QR_16_7_6_decode(unsigned char *rxBits);
void InitAllFecFunction(void);
//end borrow from LEH
void resetState (dsd_state * state);

1448
include/fec.h Normal file

File diff suppressed because it is too large Load Diff

560
src/bptc.c Normal file
View File

@@ -0,0 +1,560 @@
/*
============================================================================
Name : bptc.c
Author : MotoTRBO_Encrypted_DSD_Author
Version : 1.0
Date : 2017 - December - 11
Copyright : None
Description : BPTC library source
============================================================================
*/
/* Include ------------------------------------------------------------------*/
#include "dsd.h"
/* Define -------------------------------------------------------------------*/
/* Global variables ---------------------------------------------------------*/
const uint8_t BPTCInterleavingIndex[196] =
{
0, 181, 166, 151,
136, 121, 106, 91,
76, 61, 46, 31,
16, 1, 182, 167,
152, 137, 122, 107,
92, 77, 62, 47,
32, 17, 2, 183,
168, 153, 138, 123,
108, 93, 78, 63,
48, 33, 18, 3,
184, 169, 154, 139,
124, 109, 94, 79,
64, 49, 34, 19,
4, 185, 170, 155,
140, 125, 110, 95,
80, 65, 50, 35,
20, 5, 186, 171,
156, 141, 126, 111,
96, 81, 66, 51,
36, 21, 6, 187,
172, 157, 142, 127,
112, 97, 82, 67,
52, 37, 22, 7,
188, 173, 158, 143,
128, 113, 98, 83,
68, 53, 38, 23,
8, 189, 174, 159,
144, 129, 114, 99,
84, 69, 54, 39,
24, 9, 190, 175,
160, 145, 130, 115,
100, 85, 70, 55,
40, 25, 10, 191,
176, 161, 146, 131,
116, 101, 86, 71,
56, 41, 26, 11,
192, 177, 162, 147,
132, 117, 102, 87,
72, 57, 42, 27,
12, 193, 178, 163,
148, 133, 118, 103,
88, 73, 58, 43,
28, 13, 194, 179,
164, 149, 134, 119,
104, 89, 74, 59,
44, 29, 14, 195,
180, 165, 150, 135,
120, 105, 90, 75,
60, 45, 30, 15
};
const uint8_t BPTCDeInterleavingIndex[196] =
{
0, 13, 26, 39,
52, 65, 78, 91,
104, 117, 130, 143,
156, 169, 182, 195,
12, 25, 38, 51,
64, 77, 90, 103,
116, 129, 142, 155,
168, 181, 194, 11,
24, 37, 50, 63,
76, 89, 102, 115,
128, 141, 154, 167,
180, 193, 10, 23,
36, 49, 62, 75,
88, 101, 114, 127,
140, 153, 166, 179,
192, 9, 22, 35,
48, 61, 74, 87,
100, 113, 126, 139,
152, 165, 178, 191,
8, 21, 34, 47,
60, 73, 86, 99,
112, 125, 138, 151,
164, 177, 190, 7,
20, 33, 46, 59,
72, 85, 98, 111,
124, 137, 150, 163,
176, 189, 6, 19,
32, 45, 58, 71,
84, 97, 110, 123,
136, 149, 162, 175,
188, 5, 18, 31,
44, 57, 70, 83,
96, 109, 122, 135,
148, 161, 174, 187,
4, 17, 30, 43,
56, 69, 82, 95,
108, 121, 134, 147,
160, 173, 186, 3,
16, 29, 42, 55,
68, 81, 94, 107,
120, 133, 146, 159,
172, 185, 2, 15,
28, 41, 54, 67,
80, 93, 106, 119,
132, 145, 158, 171,
184, 1, 14, 27,
40, 53, 66, 79,
92, 105, 118, 131,
144, 157, 170, 183
};
const uint8_t DeInterleaveReverseChannelBptc[32] =
{
0, 17, 2, 19, 4, 21, 6, 23,
8, 25, 10, 27, 12, 29, 14, 31,
16, 1, 18, 3, 20, 5, 22, 7,
24, 9, 26, 11, 28, 13, 30, 15
};
/* Functions ----------------------------------------------------------------*/
/*
* @brief : This function deinterleave the DMR data by using BPTC (196,96)
*
* @param Input : Pointer of DMR input data interleaved (196 bytes)
*
* @param Output : Pointer where DMR deinterleaved data will be written (196 bytes)
*
* @return None
*/
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
{
uint32_t i, DeInterleaveIndex;
for(i = 0; i < 196; i++)
{
DeInterleaveIndex = BPTCDeInterleavingIndex[i];
Output[DeInterleaveIndex] = (Input[i] & 1);
}
} /* End BPTCDeInterleaveDMRData() */
/*
* @brief : This function extract the 96 bits of a deinteleaved 196 bits
* buffer using BPTC (196,96)
*
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (196 bytes)
*
* @param DMRDataExtracted : Pointer where the DMR data will be written (96 bytes)
*
* @return The total number of irrecoverable Hamming check errors
*/
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3])
{
uint32_t i, j, k;
uint8_t DataMatrix[13][15];
uint8_t LineUncorrected[15];
uint8_t LineCorrected[11];
uint8_t ColumnUncorrected[13];
uint8_t ColumnCorrected[9];
uint32_t HammingIrrecoverableErrorNb = 0;
/* First step : Reconstitute the BPTC 15x11 matrix
* Note : Input data shall be deinterleaved */
k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */
for(i = 0; i < 13; i++)
{
for(j = 0; j < 15; j++)
{
/* Only the LSBit of the byte is stored */
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
k++;
}
}
/* R(0) to R(2) may be used to transport some
* Restricted Access System (RAS) information,
* So save these three bytes before reset all of them
* See patent US 2013/0288643 A1 */
R[0] = DataMatrix[0][2]; /* Save R(0) */
R[1] = DataMatrix[0][1]; /* Save R(1) */
R[2] = DataMatrix[0][0]; /* Save R(2) */
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
DataMatrix[0][0] = 0; /* R(2) */
DataMatrix[0][1] = 0; /* R(1) */
DataMatrix[0][2] = 0; /* R(0) */
/* Init the Hamming (15,11,3) library
* Not needed because it has already been done
* in the "InitAllFecFunction()" function */
//Hamming_15_11_init();
/* Init the Hamming (13,9,3) library
* Not needed because it has already been done
* in the "InitAllFecFunction()" function */
//Hamming_13_9_init();
/* Init the Hamming error counter */
HammingIrrecoverableErrorNb = 0;
/* Process the the Hamming (15,11,3) code
* check on each line (first time).
* Do not check the 4th last lines */
for(i = 0; i < 9; i++)
{
/* Get a full line */
for(j = 0; j < 15; j++)
{
LineUncorrected[j] = DataMatrix[i][j];
}
/* Apply Hamming (15,11,3) code correction */
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
{
HammingIrrecoverableErrorNb++;
}
/* Re-inject the line in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 11; j++)
{
DataMatrix[i][j] = LineCorrected[j];
}
}
/* Process the the Hamming (15,11,3) code
* check on each column/row (first time) */
for(i = 0; i < 15; i++)
{
/* Get a full column */
for(j = 0; j < 13; j++)
{
ColumnUncorrected[j] = DataMatrix[j][i];
}
/* Apply Hamming (15,11,3) code correction */
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
{
HammingIrrecoverableErrorNb++;
}
/* Re-inject the column in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 9; j++)
{
DataMatrix[j][i] = ColumnCorrected[j];
}
}
/* The first Hamming code check has maybe corrected bit
* witch can be use to correct other bit, so make the
* same operation twice */
/* Reset the number of irrecoverable errors */
HammingIrrecoverableErrorNb = 0;
/* Process the the Hamming (15,11,3) code
* check on each line (second time).
* Do not check the 4th last lines */
for(i = 0; i < 9; i++)
{
/* Get a full line */
for(j = 0; j < 15; j++)
{
LineUncorrected[j] = DataMatrix[i][j];
}
/* Apply Hamming (15,11,3) code correction */
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
{
/* Row/Line contains irrecoverable errors */
HammingIrrecoverableErrorNb++;
}
else
{
/* Row/Line contains correct data */
}
/* Re-inject the line in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 11; j++)
{
DataMatrix[i][j] = LineCorrected[j];
}
}
/* Process the the Hamming (15,11,3) code
* check on each column/row (second time) */
for(i = 0; i < 15; i++)
{
/* Get a full column */
for(j = 0; j < 13; j++)
{
ColumnUncorrected[j] = DataMatrix[j][i];
}
/* Apply Hamming (15,11,3) code correction */
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
{
/* Row/Line contains irrecoverable errors */
HammingIrrecoverableErrorNb++;
}
else
{
/* Row/Line contains correct data */
}
/* Re-inject the column in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 9; j++)
{
DataMatrix[j][i] = ColumnCorrected[j];
}
}
/* Extract the DMR data (96 bit) from the matrix */
/* First line : Do not take R(2), R(1) and R(0) */
k = 0;
for(i = 3; i < 11; i++)
{
DMRDataExtracted[k] = DataMatrix[0][i];
k++;
}
/* Next lines */
for(i = 1; i < 9; i++)
{
for(j = 0; j < 11; j++)
{
DMRDataExtracted[k] = DataMatrix[i][j];
k++;
}
}
/* Return the number of irrecoverable Hamming errors */
return HammingIrrecoverableErrorNb;
} /* End BPTC_196x96_Extract_Data() */
/*
* @brief : This function extract the 77 bits of a deinteleaved 128 bits
* buffer using BPTC (128,77).
*
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.1 for details
*
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (128 bytes
act as a 16 x 8 byte data matrix)
*
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
* DMRDataExtracted[0..71] = Util data (hamming corrected)
* DMRDataExtracted[72..76] = 5 bit of CRC extracted (to be checked)
*
* @return 0 = All is OK
* Other = Error - Irrecoverable Hamming parity check error number
*/
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77])
{
uint32_t i, j, k;
uint8_t DataMatrix[8][16];
uint8_t LineUncorrected[16];
uint8_t LineCorrected[11];
uint32_t HammingIrrecoverableErrorNb = 0;
uint32_t ParityCheckErrorNb = 0;
uint32_t NbOfOne;
/* First step : Reconstitute the BPTC 16x8 matrix */
for(i = 0; i < 8; i++)
{
for(j = 0; j < 16; j++)
{
/* Only the LSBit of the byte is stored */
DataMatrix[i][j] = (InputDataMatrix[i][j] & 1);
}
}
/* Init the Hamming (16,11,4) library
* Not needed because it has already been done
* in the "InitAllFecFunction()" function */
//Hamming_16_11_4_init();
/* Process the the Hamming (16,11,4) code
* check on each line.
* Do not check the last line (line nb 8) */
for(i = 0; i < 7; i++)
{
/* Get a full line */
for(j = 0; j < 16; j++)
{
LineUncorrected[j] = DataMatrix[i][j];
}
/* Apply Hamming (16,11,4) code correction */
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
{
HammingIrrecoverableErrorNb++;
}
/* Re-inject the line in the matrix (only the util data [11 bit],
* not the Hamming part [4 bit]) */
for(j = 0; j < 11; j++)
{
DataMatrix[i][j] = LineCorrected[j];
}
}
/* Extract the DMR data (77 bit) from the matrix */
k = 0;
/* 2 first lines */
for(i = 0; i < 2; i++)
{
for(j = 0; j < 11; j++)
{
DMRDataExtracted[k] = DataMatrix[i][j];
k++;
}
}
/* 5 Next lines */
for(i = 2; i < 7; i++)
{
for(j = 0; j < 10; j++)
{
DMRDataExtracted[k] = DataMatrix[i][j];
k++;
}
}
/* 5 bit of CRC */
for(i = 2; i < 7; i++)
{
DMRDataExtracted[k] = DataMatrix[i][10];
k++;
}
/* Verify the data integrity by checking
* all column parity bit */
ParityCheckErrorNb = 0;
for(i = 0; i < 16; i++)
{
NbOfOne = 0;
/* Get a full column */
for(j = 0; j < 7; j++)
{
NbOfOne += DataMatrix[j][i];
}
/* Check the parity bit (number of "1"
* must be even) */
if((NbOfOne % 2) != DataMatrix[7][i])
{
ParityCheckErrorNb++;
}
}
/* Return the number of irrecoverable Hamming errors +
* the number of parity check error */
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
} /* End BPTC_128x77_Extract_Data() */
/*
* @brief : This function extract the 32 bits of a deinteleaved 32 bits
* buffer using Reverse Channel Single Burst BPTC.
*
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.2.2 for details
*
* @param InputInterleavedData : Pointer of DMR input data interleaved (32 bytes
act as a 16 x 2 bits data matrix)
*
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
* DMRDataExtracted[0..10] = Util data (Hamming corrected)
* DMRDataExtracted[11..15] = Hamming data
* DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked)
*
* @return 0 = All is OK
* Other = Error - Irrecoverable Hamming parity check error number
*/
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32])
{
uint32_t i;
uint8_t DataMatrix[32];
uint8_t LineUncorrected[16];
uint8_t LineCorrected[11];
uint32_t HammingIrrecoverableErrorNb = 0;
uint32_t ParityCheckErrorNb = 0;
for(i = 0; i < 32; i++)
{
DataMatrix[DeInterleaveReverseChannelBptc[i]] = InputInterleavedData[i] & 1;
}
/* Copy the entire input buffer to the output buffer */
for(i = 0; i < 32; i++)
{
DMRDataExtracted[i] = DataMatrix[i];
}
/* Prepare the line to be corrected */
for(i = 0; i < 16; i++)
{
LineUncorrected[i] = DataMatrix[i];
}
/* Apply Hamming (16,11,4) code correction */
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
{
HammingIrrecoverableErrorNb++;
}
/* Copy the corrected content to the output buffer */
for(i = 0; i < 11; i++)
{
DMRDataExtracted[i] = LineCorrected[i];
}
/* Check Parity bits */
for(i = 0; i < 16; i++)
{
/* Odd parity ==> If data = 1 then parity = 0
* If data = 0 then parity = 1 */
if(DMRDataExtracted[i] == DMRDataExtracted[i + 16]) ParityCheckErrorNb++;
}
//fprintf(stderr, "Hamming ERR=%u ; Parity ERR=%u", HammingIrrecoverableErrorNb, ParityCheckErrorNb);
/* Return the number of irrecoverable Hamming errors +
* the number of parity check error */
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
} /* End BPTC_16x2_Extract_Data() */
/* End of file */

View File

@@ -24,240 +24,407 @@ processDMRdata (dsd_opts * opts, dsd_state * state)
int i, dibit;
int *dibit_p;
char sync[25];
char syncdata[25];
char cachdata[13];
char cc[5];
char syncdata[48];
char cachdata[13] = {0};
char cc[5] = {0};
char ccAscii[5] = {0};
char bursttype[5];
int dcc_buf;
unsigned int burst;
char info[196];
char SlotType[20];
unsigned int SlotTypeOk;
/* Remove warning compiler */
//UNUSED_VARIABLE(cachdata[0]);
//UNUSED_VARIABLE(cc[0]);
//UNUSED_VARIABLE(ccAscii[0]);
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];
int k;
#endif
cc[0]=0;
cc[1]=0;
cc[2]=0;
cc[3]=0; //initialize with zeroes to prevent segfault down below
state->dmr_color_code = 0; //reset
cc[4] = 0;
ccAscii[4] = 0;
bursttype[4] = 0;
dibit_p = state->dibit_buf_p - 90;
// CACH
for (i = 0; i < 12; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
cachdata[i] = dibit;
if (i == 2)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
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;
#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++;
}
{
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);
fprintf(stderr, "%s ", cachbits);
#endif
// current slot
dibit_p += 49;
// Current slot - First half - Data Payload - 1st part
for (i = 0; i < 49; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
info[2*i] = (1 & (dibit >> 1)); // bit 1
info[(2*i)+1] = (1 & dibit); // bit 0
}
// slot type
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
//c[0] = (1 & (dibit >> 1)) + 48; // bit 1
//cc[1] = (1 & dibit) + 48; // bit 0
cc[0] = (1 & (dibit >> 1)); // bit 1
cc[1] = (1 & dibit); // bit 0
dcc_buf = 0;
//dcc_buf = (1 & (dibit >> 1)) | (1 & dibit);
dcc_buf = ((1 & (dibit >> 1)) + 48) | ((1 & dibit) + 48);
{
dibit = (dibit ^ 2);
}
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
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
//cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
//cc[3] = (1 & dibit) + 48; // bit 0
cc[2] = (1 & (dibit >> 1)); // bit 1
cc[3] = (1 & dibit); // bit 0
dcc_buf = dcc_buf << 2;
//dcc_buf = (1 & (dibit >> 1)) | (1 & dibit);
dcc_buf = ((1 & (dibit >> 1)) + 48) | ((1 & dibit) + 48);
//state->dmr_color_code = dcc_buf;
state->dmr_color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]);
//cc[2] = (1 & (dibit >> 1)); // bit 1
//cc[3] = (1 & dibit); // bit 0
{
dibit = (dibit ^ 2);
}
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)
{
dibit = (dibit ^ 2);
}
bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[1] = (1 & dibit) + 48; // bit 0
{
dibit = (dibit ^ 2);
}
// burst = (unsigned int)((1 & (dibit >> 1)) << 3);
// burst |= (unsigned int)((1 & (dibit >> 0)) << 2);
// bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1
// bursttype[1] = (1 & dibit) + 48; // bit 0
SlotType[4] = (1 & (dibit >> 1)); // bit 1
SlotType[5] = (1 & dibit); // bit 0
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1
bursttype[3] = (1 & dibit) + 48; // bit 0
{
dibit = (dibit ^ 2);
}
// burst |= (unsigned int)((1 & (dibit >> 1)) << 1);
// burst |= (unsigned int)((1 & (dibit >> 0)) << 0);
// bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1
// bursttype[3] = (1 & dibit) + 48; // bit 0
SlotType[6] = (1 & (dibit >> 1)); // bit 1
SlotType[7] = (1 & dibit); // bit 0
// parity bit
// Parity bit
dibit = *dibit_p;
dibit_p++;
if (strcmp (bursttype, "0000") == 0)
{
sprintf (state->fsubtype, " PI Header ");
}
else if (strcmp (bursttype, "0001") == 0)
{
sprintf (state->fsubtype, " VOICE Header ");
}
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, " ");
}
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
SlotType[8] = (1 & (dibit >> 1)); // bit 1
SlotType[9] = (1 & dibit); // bit 0
// signaling data or sync
for (i = 0; i < 24; i++)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
syncdata[i] = dibit;
sync[i] = (dibit | 1) + 48;
dibit = (dibit ^ 2);
}
syncdata[2*i] = (1 & (dibit >> 1)); // bit 1
syncdata[(2*i)+1] = (1 & dibit); // bit 0
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 0;
#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[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);
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) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
if (state->currentslot == 0)
{
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
sprintf(state->slot1light, "[slot1]");
}
else
{
sprintf(state->slot2light, "[slot2]");
}
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)
{
state->currentslot = 0;
sprintf(state->slot1light, "[sLoT1]");
}
else if(strcmp (sync, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
{
state->currentslot = 1;
sprintf(state->slot2light, "[sLoT2]");
}
if (opts->errorbars == 1)
{
fprintf (stderr, "%s %s ", state->slot0light, state->slot1light);
}
{
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
}
// current slot second half, cach, next slot 1st half
skipDibit (opts, state, 120);
// Slot type - Second part - Parity bit
for (i = 0; i < 5; i++)
{
dibit = getDibit(opts, state);
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
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) */
if(Golay_20_8_decode((unsigned char *)SlotType)) SlotTypeOk = 1;
else SlotTypeOk = 0;
/* Slot Type parity checked => Fill the color code */
state->color_code = (unsigned int)((cc[0] << 3) + (cc[1] << 2) + (cc[2] << 1) + cc[3]);
state->color_code_ok = SlotTypeOk;
/* Reconstitute the burst type */
burst = (unsigned int)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
/* 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';
if (strcmp (bursttype, "0000") == 0)
{
sprintf(state->fsubtype, " PI Header ");
}
else if (strcmp (bursttype, "0001") == 0)
{
sprintf(state->fsubtype, " VOICE Header ");
}
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
for (i = 0; i < 49; i++)
{
dibit = getDibit(opts, state);
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
info[(2*i) + 98] = (1 & (dibit >> 1)); // bit 1
info[(2*i) + 99] = (1 & dibit); // bit 0
}
// Skip cach (24 bit = 12 dibit) and next slot 1st half (98 + 10 bit = 49 + 5 dibit)
skipDibit (opts, state, 12 + 49 + 5);
if (opts->errorbars == 1)
{
/* Print the color code */
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
if(state->color_code_ok) fprintf(stderr, "(OK) |");
else fprintf(stderr, "(CRC ERR) |");
if (strcmp (state->fsubtype, " ") == 0)
{
if (strcmp (state->fsubtype, " ") == 0)
{
fprintf (stderr, " Unknown burst type: %s\n", bursttype);
}
else
{
fprintf (stderr, "%s\n", state->fsubtype);
}
fprintf(stderr, " Unknown burst type: %s", bursttype);
}
}
else
{
fprintf(stderr, "%s", state->fsubtype);
}
}
switch(burst)
{
/* Burst = PI header */
case 0b0000:
{
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:
{
ProcessDmrTerminaisonLC(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
break;
}
/* Burst = CSBK */
case 0b0011:
{
break;
}
/* Burst = MBC Header */
case 0b0100:
{
break;
}
/* Burst = MBC */
case 0b0101:
{
break;
}
/* Burst = DATA Header */
case 0b0110:
{
break;
}
/* Burst = RATE 1/2 DATA */
case 0b0111:
{
break;
}
/* Burst = RATE 3/4 DATA */
case 0b1000:
{
break;
}
/* Burst = Slot idle */
case 0b1001:
{
break;
}
/* Burst = Rate 1 DATA */
case 0b1010:
{
break;
}
/* Default */
default:
{
/* Nothing to do */
break;
}
} /* End switch(burst) */
if (opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
} /* End processDMRdata() */

115
src/dmr_encryption.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* 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 ProcessDMREncryption (dsd_opts * opts, dsd_state * state)
{
uint32_t i, j;
uint32_t Frame;
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL;
int *errs;
int *errs2;
/*
* Currently encryption is not supported in this public version...
*/
/* Check the current time slot */
if(state->currentslot == 0)
{
TSVoiceSupFrame = &state->TS1SuperFrame;
}
else
{
TSVoiceSupFrame = &state->TS2SuperFrame;
}
/* Apply encryption here
*
* A DMR superframe = 6 frames x 3 AMBE voice sample of 49 bits each
* uint8_t KeyStream[6][3][49];
*
* 1<>) Initialize the "KeyStream" buffer (total 882 bits) with correct bits (depending of
* encryption mode used, MotoTRBO BP, Hytera BP, MotoTRBO EP, MotoTRBO AES...
*
* 2<>) Apply a XOR between "KeyStream" and "TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i][j]"
* like code :
* for(Frame = 0; Frame < 6; Frame++)
* {
* for(i = 0; i < 3; i++)
* {
* for(j = 0; j < 49; j++)
* {
* TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i] ^= KeyStream[Frame][i][j];
* }
* }
* }
*
* 3<>) Play all AMBE decoded sample (see the "for" loop below)
*
* */
/*
* Play all AMBE voice samples
* 1 DMR voice superframe = 6 DMR frames */
for(Frame = 0; Frame < 6; Frame++)
{
/* 1 DMR frame contains 3 AMBE voice samples */
for(i = 0; i < 3; i++)
{
errs = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
errs2 = (int*)&(TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i]);
}
if (opts->errorbars == 1)
{
fprintf(stderr, "%s", state->err_str);
}
state->debug_audio_errors += *errs2;
processAudio(opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1 && opts->p25enc != 1) //play only if not equal to enc value, going to set p25enc to 1 if enc detected??
{
playSynthesizedVoice (opts, state);
}
} /* End for(i = 0; i < 3; i++) */
} /* End for(Frame = 0; Frame < 6; Frame++) */
} /* End ProcessDMREncryption() */
/* End of file */

839
src/dmr_sync.c Normal file
View File

@@ -0,0 +1,839 @@
/*
* 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"
//#define PRINT_PI_HEADER_BYTES
//#define PRINT_VOICE_LC_HEADER_BYTES
//#define PRINT_TERMINAISON_LC_BYTES
//#define PRINT_VOICE_BURST_BYTES
void ProcessDmrVoiceLcHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20])
{
uint32_t i, j, k;
uint32_t CRCExtracted = 0;
uint32_t CRCComputed = 0;
uint32_t CRCCorrect = 0;
uint32_t IrrecoverableErrors = 0;
uint8_t DeInteleavedData[196];
uint8_t DmrDataBit[96];
uint8_t DmrDataByte[12];
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL;
uint8_t R[3];
uint8_t BPTCReservedBits = 0;
/* Remove warning compiler */
//UNUSED_VARIABLE(syncdata[0]);
//UNUSED_VARIABLE(SlotType[0]);
//UNUSED_VARIABLE(BPTCReservedBits);
/* Check the current time slot */
if(state->currentslot == 0)
{
TSVoiceSupFrame = &state->TS1SuperFrame;
}
else
{
TSVoiceSupFrame = &state->TS2SuperFrame;
}
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0;
/* Deinterleave DMR data */
BPTCDeInterleaveDMRData(info, DeInteleavedData);
/* Extract the BPTC 196,96 DMR data */
IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R);
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08);
/* Convert the 96 bit of voice LC Header data into 12 bytes */
k = 0;
for(i = 0; i < 12; i++)
{
DmrDataByte[i] = 0;
for(j = 0; j < 8; j++)
{
DmrDataByte[i] = DmrDataByte[i] << 1;
DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01);
k++;
}
}
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
CRCExtracted = 0;
for(i = 0; i < 24; i++)
{
CRCExtracted = CRCExtracted << 1;
CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1);
}
/* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */
CRCExtracted = CRCExtracted ^ 0x969696;
/* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */
CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696);
/* Convert corrected 12 bytes into 96 bits */
for(i = 0, j = 0; i < 12; i++, j+=8)
{
DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01;
DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01;
DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01;
DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01;
DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01;
DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01;
DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01;
DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01;
}
/* Store the Protect Flag (PF) bit */
TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(DmrDataBit[0]);
/* Store the Reserved bit */
TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(DmrDataBit[1]);
/* Store the Full Link Control Opcode (FLCO) */
TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[2], 6);
/* Store the Feature set ID (FID) */
TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[8], 8);
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
/* Store the Service Options */
TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[16], 8);
/* Store the Group address (Talk Group) */
TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
/* Store the Source address */
TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24);
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
if((IrrecoverableErrors == 0) && CRCCorrect)
{
/* CRC is correct so consider the Full LC data as correct/valid */
TSVoiceSupFrame->FullLC.DataValidity = 1;
}
else
{
/* CRC checking error, so consider the Full LC data as invalid */
TSVoiceSupFrame->FullLC.DataValidity = 0;
}
/* Print the destination ID (TG) and the source ID */
fprintf(stderr, "| TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress);
fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
//HERE HERE do some work to get this Emergency and BP modes to display in ncurses
//state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions;
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x80) fprintf(stderr, "Emergency ");
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x40)
{
/* By default select the basic privacy (BP), if the encryption mode is EP ARC4 or AES256
* a PI Header will be sent with the encryption mode and DSD will upgrade automatically
* the new encryption mode */
opts->EncryptionMode = MODE_BASIC_PRIVACY;
fprintf(stderr, "Encrypted ");
}
else
{
opts->EncryptionMode = MODE_UNENCRYPTED;
fprintf(stderr, "Clear/Unencrypted ");
}
/* Check the "Reserved" bits */
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x30)
{
/* Experimentally determined with DSD+, when the "Reserved" bit field
* is equal to 0x2, this is a TXI call */
if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) == 0x20) fprintf(stderr, "TXI ");
else fprintf(stderr, "Reserved=%d ", (TSVoiceSupFrame->FullLC.ServiceOptions & 0x30) >> 4);
}
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x08) fprintf(stderr, "Broadcast ");
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x04) fprintf(stderr, "OVCM ");
if(TSVoiceSupFrame->FullLC.ServiceOptions & 0x03)
{
if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x01) fprintf(stderr, "Priority 1 ");
else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x02) fprintf(stderr, "Priority 2 ");
else if((TSVoiceSupFrame->FullLC.ServiceOptions & 0x03) == 0x03) fprintf(stderr, "Priority 3 ");
else fprintf(stderr, "No Priority "); /* We should never go here */
}
fprintf(stderr, "Call ");
if(TSVoiceSupFrame->FullLC.DataValidity) fprintf(stderr, "(OK) ");
else if(IrrecoverableErrors == 0) fprintf(stderr, "RAS (FEC OK/CRC ERR)");
else fprintf(stderr, "(FEC FAIL/CRC ERR)");
#ifdef PRINT_VOICE_LC_HEADER_BYTES
fprintf(stderr, "\n");
fprintf(stderr, "VOICE LC HEADER : ");
for(i = 0; i < 12; i++)
{
fprintf(stderr, "0x%02X", DmrDataByte[i]);
if(i != 11) fprintf(stderr, " - ");
}
fprintf(stderr, "\n");
fprintf(stderr, "BPTC(196,96) Reserved bit R(0)-R(2) = 0x%02X\n", BPTCReservedBits);
fprintf(stderr, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed);
if((IrrecoverableErrors == 0) && CRCCorrect)
{
fprintf(stderr, "CRCs are equal + FEC OK !\n");
}
else if(IrrecoverableErrors == 0)
{
else fprintf(stderr, "FEC correctly corrected but CRCs are incorrect\n");
}
else
{
fprintf(stderr, "ERROR !!! CRCs are different and FEC Failed !\n");
}
fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors);
#endif /* PRINT_VOICE_LC_HEADER_BYTES */
} /* End ProcessDmrVoiceLcHeader() */
void ProcessDmrTerminaisonLC(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20])
{
uint32_t i, j, k;
uint32_t CRCExtracted = 0;
uint32_t CRCComputed = 0;
uint32_t CRCCorrect = 0;
uint32_t IrrecoverableErrors = 0;
uint8_t DeInteleavedData[196];
uint8_t DmrDataBit[96];
uint8_t DmrDataByte[12];
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL;
uint8_t R[3];
uint8_t BPTCReservedBits = 0;
/* Remove warning compiler */
//UNUSED_VARIABLE(opts);
//UNUSED_VARIABLE(syncdata[0]);
//UNUSED_VARIABLE(SlotType[0]);
//UNUSED_VARIABLE(BPTCReservedBits);
/* Check the current time slot */
if(state->currentslot == 0)
{
TSVoiceSupFrame = &state->TS1SuperFrame;
}
else
{
TSVoiceSupFrame = &state->TS2SuperFrame;
}
CRCExtracted = 0;
CRCComputed = 0;
IrrecoverableErrors = 0;
/* Deinterleave DMR data */
BPTCDeInterleaveDMRData(info, DeInteleavedData);
/* Extract the BPTC 196,96 DMR data */
IrrecoverableErrors = BPTC_196x96_Extract_Data(DeInteleavedData, DmrDataBit, R);
/* Fill the reserved bit (R(0)-R(2) of the BPTC(196,96) block) */
BPTCReservedBits = (R[0] & 0x01) | ((R[1] << 1) & 0x02) | ((R[2] << 2) & 0x08);
/* Convert the 96 bit of voice LC Header data into 12 bytes */
k = 0;
for(i = 0; i < 12; i++)
{
DmrDataByte[i] = 0;
for(j = 0; j < 8; j++)
{
DmrDataByte[i] = DmrDataByte[i] << 1;
DmrDataByte[i] = DmrDataByte[i] | (DmrDataBit[k] & 0x01);
k++;
}
}
/* Fill the CRC extracted (before Reed-Solomon (12,9) FEC correction) */
CRCExtracted = 0;
for(i = 0; i < 24; i++)
{
CRCExtracted = CRCExtracted << 1;
CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1);
}
/* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */
CRCExtracted = CRCExtracted ^ 0x999999;
/* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */
CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x999999);
/* Convert corrected 12 bytes into 96 bits */
for(i = 0, j = 0; i < 12; i++, j+=8)
{
DmrDataBit[j + 0] = (DmrDataByte[i] >> 7) & 0x01;
DmrDataBit[j + 1] = (DmrDataByte[i] >> 6) & 0x01;
DmrDataBit[j + 2] = (DmrDataByte[i] >> 5) & 0x01;
DmrDataBit[j + 3] = (DmrDataByte[i] >> 4) & 0x01;
DmrDataBit[j + 4] = (DmrDataByte[i] >> 3) & 0x01;
DmrDataBit[j + 5] = (DmrDataByte[i] >> 2) & 0x01;
DmrDataBit[j + 6] = (DmrDataByte[i] >> 1) & 0x01;
DmrDataBit[j + 7] = (DmrDataByte[i] >> 0) & 0x01;
}
/* Store the Protect Flag (PF) bit */
TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(DmrDataBit[0]);
/* Store the Reserved bit */
TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(DmrDataBit[1]);
/* Store the Full Link Control Opcode (FLCO) */
TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[2], 6);
/* Store the Feature set ID (FID) */
TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[8], 8);
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
/* Store the Service Options */
TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[16], 8);
/* Store the Group address (Talk Group) */
TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[24], 24);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
/* Store the Source address */
TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[48], 24);
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
if((IrrecoverableErrors == 0))// && CRCCorrect)
{
/* CRC is correct so consider the Full LC data as correct/valid */
TSVoiceSupFrame->FullLC.DataValidity = 1;
}
else
{
/* CRC checking error, so consider the Full LC data as invalid */
TSVoiceSupFrame->FullLC.DataValidity = 0;
}
/* Print the destination ID (TG) and the source ID */
fprintf(stderr, "| TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress);
fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
if((IrrecoverableErrors == 0) && CRCCorrect)
{
fprintf(stderr, "(OK) ");
//only set on good CRC value or corrected values
state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions;
state->dmr_color_code = state->color_code;
}
else if(IrrecoverableErrors == 0)
{
fprintf(stderr, "RAS (FEC OK/CRC ERR)");
//only set on good CRC value or corrected values
state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions;
state->dmr_color_code = state->color_code;
}
else fprintf(stderr, "(FEC FAIL/CRC ERR)");
#ifdef PRINT_TERMINAISON_LC_BYTES
fprintf(stderr, "\n");
fprintf(stderr, "TERMINAISON LINK CONTROL (TLC) : ");
for(i = 0; i < 12; i++)
{
fprintf(stderr, "0x%02X", DmrDataByte[i]);
if(i != 11) fprintf(stderr, " - ");
}
fprintf(stderr, "\n");
fprintf(stderr, "BPTC(196,96) Reserved bit R(0)-R(2) = 0x%02X\n", BPTCReservedBits);
fprintf(stderr, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed);
if((IrrecoverableErrors == 0) && CRCCorrect)
{
fprintf(stderr, "CRCs are equal + FEC OK !\n");
}
else if(IrrecoverableErrors == 0)
{
else fprintf(stderr, "FEC correctly corrected but CRCs are incorrect\n");
}
else
{
fprintf(stderr, "ERROR !!! CRCs are different and FEC Failed !\n");
}
fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors);
#endif /* PRINT_TERMINAISON_LC_BYTES */
} /* End ProcessDmrTerminaisonLC() */
/* Extract the Link Control (LC) embedded in the SYNC
* of a DMR voice superframe */
void ProcessVoiceBurstSync(dsd_opts * opts, dsd_state * state)
{
uint32_t i, j, k;
uint32_t Burst;
uint8_t BptcDataMatrix[8][16];
uint8_t LC_DataBit[77];
uint8_t LC_DataBytes[10];
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrame = NULL;
uint32_t IrrecoverableErrors;
uint8_t CRCExtracted;
uint8_t CRCComputed;
uint32_t CRCCorrect = 0;
/* Remove warning compiler */
//UNUSED_VARIABLE(opts);
/* Check the current time slot */
if(state->currentslot == 0)
{
TSVoiceSupFrame = &state->TS1SuperFrame;
}
else
{
TSVoiceSupFrame = &state->TS2SuperFrame;
}
/* 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] = TSVoiceSupFrame->TimeSlotRawVoiceFrame[Burst].Sync[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);
/* Convert the 77 bit of voice LC Header data into 9 bytes */
k = 0;
for(i = 0; i < 10; i++)
{
LC_DataBytes[i] = 0;
for(j = 0; j < 8; j++)
{
LC_DataBytes[i] = LC_DataBytes[i] << 1;
LC_DataBytes[i] = LC_DataBytes[i] | (LC_DataBit[k] & 0x01);
k++;
if(k >= 76) break;
}
}
/* 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;
/* Store the Protect Flag (PF) bit */
TSVoiceSupFrame->FullLC.ProtectFlag = (unsigned int)(LC_DataBit[0]);
/* Store the Reserved bit */
TSVoiceSupFrame->FullLC.Reserved = (unsigned int)(LC_DataBit[1]);
/* Store the Full Link Control Opcode (FLCO) */
TSVoiceSupFrame->FullLC.FullLinkControlOpcode = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[2], 6);
/* Store the Feature set ID (FID) */
TSVoiceSupFrame->FullLC.FeatureSetID = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[8], 8);
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
/* Store the Service Options */
TSVoiceSupFrame->FullLC.ServiceOptions = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[16], 8);
/* Store the Group address (Talk Group) */
TSVoiceSupFrame->FullLC.GroupAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[24], 24);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
/* Store the Source address */
TSVoiceSupFrame->FullLC.SourceAddress = (unsigned int)ConvertBitIntoBytes(&LC_DataBit[48], 24);
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
/* Check the CRC values */
if((IrrecoverableErrors == 0))// && CRCCorrect)
{
/* Data ara correct */
//fprintf(stderr, "\nLink Control (LC) Data CRCs are correct !!! Number of error = %u\n", NbOfError);
/* CRC is correct so consider the Full LC data as correct/valid */
TSVoiceSupFrame->FullLC.DataValidity = 1;
}
else
{
/* CRC checking error, so consider the Full LC data as invalid */
TSVoiceSupFrame->FullLC.DataValidity = 0;
}
/* Print the destination ID (TG) and the source ID */
fprintf(stderr, "| TG=%u Src=%u ", TSVoiceSupFrame->FullLC.GroupAddress, TSVoiceSupFrame->FullLC.SourceAddress);
fprintf(stderr, "FID=0x%02X ", TSVoiceSupFrame->FullLC.FeatureSetID);
//state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
//state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
//state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
if((IrrecoverableErrors == 0) && CRCCorrect)
{
fprintf(stderr, "(OK)");
//only set on good CRC?
state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions;
state->dmr_color_code = state->color_code;
}
else if(IrrecoverableErrors == 0)
{
fprintf(stderr, "RAS (FEC OK/CRC ERR)");
//or set if was corrected
state->lasttg = TSVoiceSupFrame->FullLC.GroupAddress;
state->lastsrc = TSVoiceSupFrame->FullLC.SourceAddress;
state->dmr_fid = TSVoiceSupFrame->FullLC.FeatureSetID;
state->dmr_so = TSVoiceSupFrame->FullLC.ServiceOptions;
state->dmr_color_code = state->color_code;
}
else fprintf(stderr, "(FEC FAIL/CRC ERR)");
#ifdef PRINT_VOICE_BURST_BYTES
fprintf(stderr, "\n");
fprintf(stderr, "VOICE BURST BYTES : ");
for(i = 0; i < 10; i++)
{
fprintf(stderr, "0x%02X", LC_DataBytes[i]);
if(i != 9) fprintf(stderr, " - ");
}
fprintf(stderr, "\n");
fprintf(stderr, "CRC extracted = 0x%04X - CRC computed = 0x%04X - ", CRCExtracted, CRCComputed);
if((IrrecoverableErrors == 0) && CRCCorrect)
{
fprintf(stderr, "CRCs are equal + FEC OK !\n");
}
else if(IrrecoverableErrors == 0)
{
else fprintf(stderr, "FEC correctly corrected but CRCs are incorrect\n");
}
else
{
fprintf(stderr, "ERROR !!! CRCs are different and FEC Failed !\n");
}
fprintf(stderr, "Hamming Irrecoverable Errors = %u\n", IrrecoverableErrors);
#endif /* PRINT_VOICE_BURST_BYTES */
} /* End ProcessVoiceBurstSync() */
/*
* @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() */
/*
* @brief : This function returns the Algorithm ID into an explicit string
*
* @param AlgID : The algorithm ID
* @arg : 0x21 for ARC4
* @arg : 0x22 for DES
* @arg : 0x25 for AES256
*
* @return A constant string pointer that explain the Alg ID used
*/
uint8_t * DmrAlgIdToStr(uint8_t AlgID)
{
if(AlgID == 0x21) return (uint8_t *)"ARC4";
else if(AlgID == 0x25) return (uint8_t *)"AES256";
else return (uint8_t *)"UNKNOWN";
//state->payload_algid = AlgID;
} /* End DmrAlgIdToStr */
/*
* @brief : This function returns the encryption mode into an explicit string
*
* @param PrivacyMode : The algorithm ID
* @arg : MODE_UNENCRYPTED
* @arg : MODE_BASIC_PRIVACY
* @arg : MODE_ENHANCED_PRIVACY_ARC4
* @arg : MODE_ENHANCED_PRIVACY_DES
* @arg : MODE_ENHANCED_PRIVACY_AES256
* @arg : MODE_HYTERA_BASIC_40_BIT
* @arg : MODE_HYTERA_BASIC_128_BIT
* @arg : MODE_HYTERA_BASIC_256_BIT
*
* @return A constant string pointer that explain the encryption mode used
*/
uint8_t * DmrAlgPrivacyModeToStr(uint32_t PrivacyMode)
{
switch(PrivacyMode)
{
case MODE_UNENCRYPTED:
{
return (uint8_t *)"NOT ENC";
break;
}
case MODE_BASIC_PRIVACY:
{
return (uint8_t *)"BP";
break;
}
case MODE_ENHANCED_PRIVACY_ARC4:
{
return (uint8_t *)"EP ARC4";
break;
}
case MODE_ENHANCED_PRIVACY_AES256:
{
return (uint8_t *)"EP AES256";
break;
}
case MODE_HYTERA_BASIC_40_BIT:
{
return (uint8_t *)"HYTERA BASIC 40 BIT";
break;
}
case MODE_HYTERA_BASIC_128_BIT:
{
return (uint8_t *)"HYTERA BASIC 128 BIT";
break;
}
case MODE_HYTERA_BASIC_256_BIT:
{
return (uint8_t *)"HYTERA BASIC 256 BIT";
break;
}
default:
{
return (uint8_t *)"UNKNOWN";
break;
}
} /* End switch(PrivacyMode) */
} /* End DmrAlgPrivacyModeToStr() */
/* End of file */

View File

@@ -18,365 +18,633 @@
#include "dsd.h"
#include "dmr_const.h"
void
processDMRvoice (dsd_opts * opts, dsd_state * state)
void processDMRvoice (dsd_opts * opts, dsd_state * state)
{
// extracts AMBE frames from DMR frame
int i, j, dibit;
int i, j, k, l, dibit;
int *dibit_p;
char ambe_fr[4][24];
char ambe_fr2[4][24];
char ambe_fr3[4][24];
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[25];
char cachdata[13];
char syncdata[48];
char cachdata[13] = {0};
int mutecurrentslot;
int msMode;
char cc[4];
unsigned char EmbeddedSignalling[16];
unsigned int EmbeddedSignallingOk;
/* Remove warning compiler */
//UNUSED_VARIABLE(ambe_fr[0][0]);
//UNUSED_VARIABLE(ambe_fr2[0][0]);
//UNUSED_VARIABLE(ambe_fr3[0][0]);
//UNUSED_VARIABLE(cachdata[0]);
#ifdef DMR_DUMP
int k;
char syncbits[49];
char cachbits[25];
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++)
for(j = 0; j < 6; j++)
{
// 2nd half of previous slot
for(i = 0; i < 54; i++)
{
// 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)
{
if (j > 0)
{
dibit = getDibit (opts, state);
}
else
{
dibit = *dibit_p;
dibit_p++;
if (opts->inverted_dmr == 1)
{
dibit = (dibit ^ 2);
}
}
dibit = (dibit ^ 2);
}
}
}
// CACH
for (i = 0; i < 12; i++)
// 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)
{
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)
{
state->currentslot = (1 & (dibit >> 1)); // bit 1
if (state->currentslot == 0)
{
state->slot0light[0] = '[';
state->slot0light[6] = ']';
state->slot1light[0] = ' ';
state->slot1light[6] = ' ';
}
else
{
state->slot1light[0] = '[';
state->slot1light[6] = ']';
state->slot0light[0] = ' ';
state->slot0light[6] = ' ';
}
}
dibit = (dibit ^ 2);
}
cachdata[12] = 0;
}
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;
#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);
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;
for (i = 0; i < 36; i++)
// 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)
{
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
w++;
x++;
y++;
z++;
dibit = (dibit ^ 2);
}
}
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[*y][*z] = (1 & dibit); // bit 0
// current slot frame 2 first half
w = rW;
x = rX;
y = rY;
z = rZ;
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
w++;
x++;
y++;
z++;
}
/* 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
// 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[i] = dibit;
sync[i] = (dibit | 1) + 48;
}
sync[24] = 0;
syncdata[24] = 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
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
mutecurrentslot = 1;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[slot0]");
}
else
{
sprintf (state->slot1light, "[slot1]");
}
}
else if ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_VOICE_SYNC) == 0))
{
mutecurrentslot = 0;
if (state->currentslot == 0)
{
sprintf (state->slot0light, "[SLOT0]");
}
else
{
sprintf (state->slot1light, "[SLOT1]");
}
}
if ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
msMode = 1;
}
/* 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
}
if ((j == 0) && (opts->errorbars == 1))
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)
{
fprintf (stderr, "%s %s VOICE e:", state->slot0light, state->slot1light);
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]");
}
if((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
{
msMode = 1;
}
// TODO : To be removed
// if((j == 0) && (opts->errorbars == 1))
// {
// fprintf(stderr, "%s %s VOICE e:", state->slot1light, state->slot2light);
// }
#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);
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
w++;
x++;
y++;
z++;
}
// 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
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);
}
}
/* 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
// current slot frame 3
w = rW;
x = rX;
y = rY;
z = rZ;
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
w++;
x++;
y++;
z++;
}
if (mutecurrentslot == 0)
{
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
}
/* 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
// CACH
for (i = 0; i < 12; i++)
{
dibit = getDibit (opts, state);
cachdata[i] = dibit;
}
cachdata[12] = 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);
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
// 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)
{
// 2nd half 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;
// CACH
skipDibit (opts, state, 12);
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1))
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " slot1 ");
}
else
{
sprintf (state->slot0light, " slot0 ");
}
}
else if (strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
{
if (state->currentslot == 0)
{
sprintf (state->slot1light, " SLOT1 ");
}
else
{
sprintf (state->slot0light, " SLOT0 ");
}
}
#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)
{
// 2nd half next slot
skipDibit (opts, state, 54);
// CACH
skipDibit (opts, state, 12);
// first half current slot
skipDibit (opts, state, 54);
}
// first half current slot
skipDibit (opts, state, 54);
}
if (opts->errorbars == 1)
/* Extract the 49 bits AMBE of the voice frame */
if(state->currentslot == 0)
{
fprintf (stderr, "\n");
/* 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->errs = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; //correct placement
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
//state->errs2 = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i]; //correct placement
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]));
}
//state->errs = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; //correct placement
//state->errs2 = (int)state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i]; //correct placement
}
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->errs = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; //correct placement
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
//state->errs2 = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i]; //correct placement
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]));
}
//state->errs = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i]; //correct placement
//state->errs2 = (int)state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i]; //correct placement
}
} /* 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, "| Color Code=%02d ", (int)state->color_code);
if(state->color_code_ok) fprintf(stderr, "(OK) |");
else fprintf(stderr, "(CRC ERR) |");
fprintf(stderr, " VOICE e:");
}
/* Perform the SYNC DMR data embedded decoding */
ProcessVoiceBurstSync(opts, state);
/* Perform the DMR encryption decoding */
ProcessDMREncryption(opts, state);
/* Print DMR frame (if needed) */
//DMRVoiceFrameProcess(opts, state); //HERE HERE, was enabled, disabled so I could build
if(opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
} /* End processDMRvoice() */

278
src/dpmr_data.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* 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"
/* Convert the Channel code (24 bit) into a valid
* dPMR color code [0..63]
* Return -1 on error */
int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24])
{
uint32_t ChannelCodeByte;
int32_t ColorCode;
uint32_t i;
/* Reconstitute the 24 bit channel code into a 3 bytes integer */
ChannelCodeByte = 0;
for(i = 0; i < 24; i++)
{
ChannelCodeByte <<= 1;
ChannelCodeByte |= (ChannelCodeBit[i] & 1);
}
/* By analyzing all channel code on the
* dPMR standard, I observe that if we decompose the
* 24 bit into 12 dibit, all dibit's LSB are always
* equal to "1", so apply a mask to correct
* flipped LSB dibit.
*
* For more details see ETSI TS 102 658 chapter
* 6.1.5.2.2 "Channel Code Determined by Frequency
* and System Identity Code".
*
* Apply the mask 0x555555
* 0x555555 = 0b010101010101010101010101 => All dibit's LSB
* are equal to "1".
*/
ChannelCodeByte |= 0x555555;
/* Switch to the right color code */
switch(ChannelCodeByte & 0xFF0000)
{
case 0x570000:
{
switch(ChannelCodeByte)
{
case 0x575F77: {ColorCode = 0; break;}
case 0x577577: {ColorCode = 1; break;}
case 0x57DD75: {ColorCode = 2; break;}
case 0x57F775: {ColorCode = 3; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x570000 */
case 0x550000:
{
switch(ChannelCodeByte)
{
case 0x55577D: {ColorCode = 4; break;}
case 0x557D7D: {ColorCode = 5; break;}
case 0x55D57F: {ColorCode = 6; break;}
case 0x55FF7F: {ColorCode = 7; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x550000 */
case 0x5F0000:
{
switch(ChannelCodeByte)
{
case 0x5F555F: {ColorCode = 8; break;}
case 0x5F7F5F: {ColorCode = 9; break;}
case 0x5FD75D: {ColorCode = 10; break;}
case 0x5FFD5D: {ColorCode = 11; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x5F0000 */
case 0x5D0000:
{
switch(ChannelCodeByte)
{
case 0x5D5D55: {ColorCode = 12; break;}
case 0x5D7755: {ColorCode = 13; break;}
case 0x5DDF57: {ColorCode = 14; break;}
case 0x5DF557: {ColorCode = 15; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x5D0000 */
case 0x770000:
{
switch(ChannelCodeByte)
{
case 0x775DD7: {ColorCode = 16; break;}
case 0x7777D7: {ColorCode = 17; break;}
case 0x77DFD5: {ColorCode = 18; break;}
case 0x77F5D5: {ColorCode = 19; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x770000 */
case 0x750000:
{
switch(ChannelCodeByte)
{
case 0x7555DD: {ColorCode = 20; break;}
case 0x757FDD: {ColorCode = 21; break;}
case 0x75D7DF: {ColorCode = 22; break;}
case 0x75FDDF: {ColorCode = 23; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x750000 */
case 0x7F0000:
{
switch(ChannelCodeByte)
{
case 0x7F57FF: {ColorCode = 24; break;}
case 0x7F7DFF: {ColorCode = 25; break;}
case 0x7FD5FD: {ColorCode = 26; break;}
case 0x7FFFFD: {ColorCode = 27; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x7F0000 */
case 0x7D0000:
{
switch(ChannelCodeByte)
{
case 0x7D5FF5: {ColorCode = 28; break;}
case 0x7D75F5: {ColorCode = 29; break;}
case 0x7DDDF7: {ColorCode = 30; break;}
case 0x7DF7F7: {ColorCode = 31; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0x7D0000 */
case 0xD70000:
{
switch(ChannelCodeByte)
{
case 0xD755F7: {ColorCode = 32; break;}
case 0xD77FF7: {ColorCode = 33; break;}
case 0xD7D7F5: {ColorCode = 34; break;}
case 0xD7FDF5: {ColorCode = 35; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xD70000 */
case 0xD50000:
{
switch(ChannelCodeByte)
{
case 0xD55DFD: {ColorCode = 36; break;}
case 0xD577FD: {ColorCode = 37; break;}
case 0xD5DFFF: {ColorCode = 38; break;}
case 0xD5F5FF: {ColorCode = 39; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xD50000 */
case 0xDF0000:
{
switch(ChannelCodeByte)
{
case 0xDF5FDF: {ColorCode = 40; break;}
case 0xDF75DF: {ColorCode = 41; break;}
case 0xDFDDDD: {ColorCode = 42; break;}
case 0xDFF7DD: {ColorCode = 43; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xDF0000 */
case 0xDD0000:
{
switch(ChannelCodeByte)
{
case 0xDD57D5: {ColorCode = 44; break;}
case 0xDD7DD5: {ColorCode = 45; break;}
case 0xDDD5D7: {ColorCode = 46; break;}
case 0xDDFFD7: {ColorCode = 47; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xDD0000 */
case 0xF70000:
{
switch(ChannelCodeByte)
{
case 0xF75757: {ColorCode = 48; break;}
case 0xF77D57: {ColorCode = 49; break;}
case 0xF7D555: {ColorCode = 50; break;}
case 0xF7FF55: {ColorCode = 51; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xF70000 */
case 0xF50000:
{
switch(ChannelCodeByte)
{
case 0xF55F5D: {ColorCode = 52; break;}
case 0xF5755D: {ColorCode = 53; break;}
case 0xF5DD5F: {ColorCode = 54; break;}
case 0xF5F75F: {ColorCode = 55; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xF50000 */
case 0xFF0000:
{
switch(ChannelCodeByte)
{
case 0xFF5D7F: {ColorCode = 56; break;}
case 0xFF777F: {ColorCode = 57; break;}
case 0xFFDF7D: {ColorCode = 58; break;}
case 0xFFF57D: {ColorCode = 59; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xFF0000 */
case 0xFD0000:
{
switch(ChannelCodeByte)
{
case 0xFD5575: {ColorCode = 60; break;}
case 0xFD7F75: {ColorCode = 61; break;}
case 0xFDD777: {ColorCode = 62; break;}
case 0xFDFD77: {ColorCode = 63; break;}
default: {ColorCode = -1; break;}
} /* End switch(ChannelCodeByte) */
break;
} /* End case 0xFD0000 */
default:
{
ColorCode = -1;
break;
}
} /* End switch(ChannelCodeByte & 0xFF0000) */
/* Return the colour code */
return ColorCode;
}
/* End of file */

919
src/dpmr_voice.c Normal file
View File

@@ -0,0 +1,919 @@
/*
* 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 "dpmr_const.h"
/* Uncomment this define to display the dPMR debug info */
//#define dPMR_PRINT_DEBUG_INFO
void processdPMRvoice (dsd_opts * opts, dsd_state * state)
{
// extracts AMBE frames from DMR frame
uint32_t i, j, k, dibit;
uint8_t CCH[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDescrambled[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDeInterleaved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][72] = {0};
uint8_t CCHDataHammingCorrected[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][48] = {0};
uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
//uint8_t TCH[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][72] = {0};
uint8_t CC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE / 2][24] = {0};
char ambe_fr[NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4][4][24] = {0};
char ambe_fr2[4][24];
const int *w, *x, *y, *z;
uint32_t ScramblerLFSR = 0;
bool correctable = true;
bool HammingCorrectable[NB_OF_DPMR_VOICE_FRAME_TO_DECODE][6] = {0};
uint32_t CrcOk[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
uint32_t HammingOk[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
uint32_t Temp = 0;
/* CCH (Control CHannel) data */
uint32_t CCH_FrameNumber[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
uint32_t CCH_CalledID = 0;
uint32_t CCH_CallingID = 0;
uint32_t CCH_CommunicationMode[NB_OF_DPMR_VOICE_FRAME_TO_DECODE] = {0};
uint32_t CCH_Version[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_CommsFormat[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_EmergencyPriority[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_Reserved[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t CCH_SlowData[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
uint32_t *errs;
uint32_t *errs2;
uint8_t AmbeBitDescrambled[49] = {0};
uint32_t ScramblerKey = 0;
uint32_t PartOfSuperFrame = 0;
uint32_t VoiceFrameFlag = 1; /* We consider the current frame as a voice frame */
uint32_t AttachedDataFlag = 0;
uint8_t CalledID[8] = {0};
uint8_t CallingID[8] = {0};
/* Remove compiler warning */
//UNUSED_VARIABLE(AmbeBitDescrambled[0]);
//UNUSED_VARIABLE(ScramblerKey);
//UNUSED_VARIABLE(PartOfSuperFrame);
if (opts->errorbars == 1)
{
fprintf(stderr, "VOICE e:");
}
/* First CCH (Control CHannel) - 72 bit */
k = 0;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
if (opts->inverted_dpmr == 1)
{
dibit = (dibit ^ 2);
}
CCH[0][(i * 2)] = (1 & (dibit >> 1)); // bit 1
CCH[0][(i * 2) + 1] = (1 & dibit); // bit 0
#ifdef DPMR_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
}
#ifdef DPMR_DUMP
fprintf(stderr, " ");
#endif
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
k = 0;
for (j = 0; j < 4; j++)
{
w = dPmrW;
x = dPmrX;
y = dPmrY;
z = dPmrZ;
k = 0;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
if (opts->inverted_dpmr == 1)
{
dibit = (dibit ^ 2);
}
#ifdef DPMR_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
ambe_fr[j][*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[j][*y][*z] = (1 & dibit); // bit 0
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
//TCH[j][k] = (1 & (dibit >> 1)); // bit 1
//TCH[j][k + 1] = (1 & dibit); // bit 0
state->dPMRVoiceFS2Frame.RawVoiceBit[j][k] = (1 & (dibit >> 1)); // bit 1
state->dPMRVoiceFS2Frame.RawVoiceBit[j][k + 1] = (1 & dibit); // bit 0
k = k + 2;
w++;
x++;
y++;
z++;
}
//processMbeFrame (opts, state, NULL, ambe_fr[j], NULL); //HERE HERE
#ifdef DPMR_DUMP
fprintf(stderr, " ");
#endif
}
/* First CC (Channel Code) - 24 bit */
k = 0;
for (i = 0; i < 12; i++)
{
dibit = getDibit (opts, state);
if (opts->inverted_dpmr == 1)
{
dibit = (dibit ^ 2);
}
CC[0][k++] = (1 & (dibit >> 1)); // bit 1
CC[0][k++] = (1 & dibit); // bit 0
#ifdef DPMR_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
}
#ifdef DPMR_DUMP
fprintf(stderr, " ");
#endif
/* Get the color code */
state->dPMRVoiceFS2Frame.ColorCode[0] = (unsigned int)GetdPmrColorCode(CC[0]);
/* Second CCH (Control CHannel) - 72 bit */
k = 0;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
if (opts->inverted_dpmr == 1)
{
dibit = (dibit ^ 2);
}
CCH[1][k++] = (1 & (dibit >> 1)); // bit 1
CCH[1][k++] = (1 & dibit); // bit 0
#ifdef DPMR_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
}
#ifdef DPMR_DUMP
fprintf(stderr, " ");
#endif
/* 4 TCH (Traffic CHannel) = 4 x 72 bit voice playload */
k = 0;
for (j = 0; j < 4; j++)
{
w = dPmrW;
x = dPmrX;
y = dPmrY;
z = dPmrZ;
k = 0;
for (i = 0; i < 36; i++)
{
dibit = getDibit (opts, state);
if (opts->inverted_dpmr == 1)
{
dibit = (dibit ^ 2);
}
#ifdef DPMR_DUMP
fprintf(stderr, "%c", dibit + 48);
#endif
ambe_fr[j + 4][*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[j + 4][*y][*z] = (1 & dibit); // bit 0
//TCH[j + 4][k] = (1 & (dibit >> 1)); // bit 1
//TCH[j + 4][k + 1] = (1 & dibit); // bit 0
state->dPMRVoiceFS2Frame.RawVoiceBit[j + 4][k] = (1 & (dibit >> 1)); // bit 1
state->dPMRVoiceFS2Frame.RawVoiceBit[j + 4][k + 1] = (1 & dibit); // bit 0
k = k + 2;
w++;
x++;
y++;
z++;
}
#ifdef DPMR_DUMP
fprintf(stderr, " ");
#endif
}
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* Initialize the Hamming (12,8) error code detection
* Not needed because it has already been done
* in the "InitAllFecFunction()" function */
//Hamming_12_8_init();
/* Decoding all CCH (Control CHannel) */
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
/* Init LFSR value - All bit to '1' */
ScramblerLFSR = 0x1FF;
/* Descramble data - Input 72 bit => Output 72 bit */
ScrambledPMRBit(&ScramblerLFSR, CCH[i], CCHDescrambled[i], 72);
/* Deinterleave data - Input 72 bit => Output 72 bit */
DeInterleave6x12DPmrBit(CCHDescrambled[i], CCHDeInterleaved[i]);
correctable = true;
for(j = 0; j < 6; j++)
{
/* Apply the Hamming(12,8) correction - Input 72 bit => Output 48 bit */
HammingCorrectable[i][j] = Hamming_12_8_decode(&CCHDeInterleaved[i][j*12], &CCHDataHammingCorrected[i][j*8], 1);
if(HammingCorrectable[i][j] == false) correctable = false;
}
if(correctable)
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "CCH data corrected successfully\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
HammingOk[i] = 1;
}
else
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "ERROR !!! CCH data contains uncorrectable bit\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
HammingOk[i] = 0;
}
/* Reconstitute the 7 bit CRC */
CCHDataCRC[i] = 0;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][41]) << 6;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][42]) << 5;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][43]) << 4;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][44]) << 3;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][45]) << 2;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][46]) << 1;
CCHDataCRC[i] |= (CCHDataHammingCorrected[i][47]) << 0;
/* Compute the 7 bit CRC */
CCHDataCRCComputed[i] = CRC7BitdPMR(CCHDataHammingCorrected[i], 41);
if(CCHDataCRC[i] == CCHDataCRCComputed[i])
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Good CCH CRCs ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
CCHDataCRC[i], CCHDataCRCComputed[i]);
#endif /* dPMR_PRINT_DEBUG_INFO */
CrcOk[i] = 1;
}
else
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "ERROR !!! CCH CRCs are different ! CRC received = 0x%02X, CRC computed = 0x%02X\n",
CCHDataCRC[i], CCHDataCRCComputed[i]);
#endif /* dPMR_PRINT_DEBUG_INFO */
CrcOk[i] = 0;
}
/* Fill the frame number */
CCH_FrameNumber[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][0], 2);
/* Fill the communication mode */
CCH_CommunicationMode[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][14], 3);
/* Fill the version */
CCH_Version[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][17], 2);
/* Fill the comm format */
CCH_CommsFormat[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][19], 2);
/* Fill the emergency priority bit */
CCH_EmergencyPriority[i] = (uint32_t)CCHDataHammingCorrected[i][21];
/* Fill the reserved bit */
CCH_Reserved[i] = (uint32_t)CCHDataHammingCorrected[i][22];
/* Fill the slow data */
CCH_SlowData[i] = ConvertBitIntoBytes(&CCHDataHammingCorrected[i][23], 18);
/* Copy the CCH data into the structure */
memcpy(state->dPMRVoiceFS2Frame.CCHData[i], CCHDataHammingCorrected[i], 48);
state->dPMRVoiceFS2Frame.CCHDataHammingOk[i] = HammingOk[i];
state->dPMRVoiceFS2Frame.CCHDataCRC[i] = CCHDataCRC[i];
state->dPMRVoiceFS2Frame.CCHDataCrcOk[i] = CrcOk[i];
state->dPMRVoiceFS2Frame.FrameNumbering[i] = CCH_FrameNumber[i];
state->dPMRVoiceFS2Frame.CommunicationMode[i] = CCH_CommunicationMode[i];
state->dPMRVoiceFS2Frame.Version[i] = CCH_Version[i];
state->dPMRVoiceFS2Frame.CommsFormat[i] = CCH_CommsFormat[i];
state->dPMRVoiceFS2Frame.EmergencyPriority[i] = CCH_EmergencyPriority[i];
state->dPMRVoiceFS2Frame.Reserved[i] = CCH_Reserved[i];
state->dPMRVoiceFS2Frame.SlowData[i] = CCH_SlowData[i];
} /* End for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++) */
/* Get the last TG */
strcpy((char *)CalledID, (char *)state->dPMRVoiceFS2Frame.CalledID);
CalledID[7] = '\0';
/* Get the last source ID */
strcpy((char *)CallingID, (char *)state->dPMRVoiceFS2Frame.CallingID);
CallingID[7] = '\0';
#ifdef dPMR_PRINT_DEBUG_INFO
/* Print Hamming debug info */
fprintf(stderr, " | ");
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
fprintf(stderr, "Hamming[%u]=", i);
for(j = 0; j < 6; j++)
{
if(HammingCorrectable[i][j]) fprintf(stderr, "1");
else fprintf(stderr, "0");
}
fprintf(stderr, " HammingOk[%u]=%u", i, HammingOk[i]);
fprintf(stderr, " CrcOk[%u]=%u", i, CrcOk[i]);
//fprintf(stderr, " Bit[%u]=", i);
//for(j = 0; j < 7; j++)
//{
// if(CCHDataHammingCorrected[i][j + 41]) fprintf(stderr, "1");
// else fprintf(stderr, "0");
//}
fprintf(stderr, " CRCrec=0x%02X CRCcomp=0x%02X", CCHDataCRC[i], CCHDataCRCComputed[i]);
if(i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE - 1)) fprintf(stderr, " - ");
}
#endif /* dPMR_PRINT_DEBUG_INFO */
#if (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2)
/* To determine the part of the payload frame, we need to check the
* Hamming code result, the CRC and the frame number */
// if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 0)) ||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 1)))
if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 0)) ||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 1)))
{
/* First part of the super frame */
PartOfSuperFrame = 1;
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "First part of the Super Frame\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* The next part will normally be the second part */
opts->dPMR_next_part_of_superframe = 2;
/* Fill the called ID (talk group - TG) */
Temp = ConvertBitIntoBytes(&CCHDataHammingCorrected[0][2], 12);
CCH_CalledID = ((Temp << 12) & 0x00FFF000); /* 12 MSBit */
Temp = ConvertBitIntoBytes(&CCHDataHammingCorrected[1][2], 12);
CCH_CalledID |= (Temp & 0x00000FFF); /* 12 LSBit */
ConvertAirInterfaceID(CCH_CalledID, CalledID);
CalledID[7] = '\0';
/* Determine if the called TG ID only is correct */
//if(HammingOk[0] && CrcOk[0] && HammingOk[1] && CrcOk[1])
if((CrcOk[0] || (HammingCorrectable[0][0] && HammingCorrectable[0][1])) &&
(CrcOk[1] || (HammingCorrectable[1][0] && HammingCorrectable[1][1])))
{
/* Save CCH data parameters */
state->dPMRVoiceFS2Frame.CalledIDOk = 1;
}
else
{
state->dPMRVoiceFS2Frame.CalledIDOk = 0;
}
/* BUGFIX : Copy in all case the TG ID */
strcpy((char *)state->dPMRVoiceFS2Frame.CalledID, (char *)CalledID);
}
/* To determine the part of the payload frame, we need to check the
* Hamming code result, the CRC and the frame number */
// else if( (HammingOk[0] && CrcOk[0] && (CCH_FrameNumber[0] == 2)) ||
// (HammingOk[1] && CrcOk[1] && (CCH_FrameNumber[1] == 3)))
else if(((CrcOk[0] || HammingCorrectable[0][0]) && (CCH_FrameNumber[0] == 2)) ||
((CrcOk[1] || HammingCorrectable[1][0]) && (CCH_FrameNumber[1] == 3)))
{
/* Second part of the super frame */
PartOfSuperFrame = 2;
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Second part of the Super Frame\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* The next part will normally be the first part */
opts->dPMR_next_part_of_superframe = 1;
/* Fill the calling ID (source) */
Temp = ConvertBitIntoBytes(&CCHDataHammingCorrected[0][2], 12);
CCH_CallingID = ((Temp << 12) & 0x00FFF000); /* 12 MSBit */
Temp = ConvertBitIntoBytes(&CCHDataHammingCorrected[1][2], 12);
CCH_CallingID |= (Temp & 0x00000FFF); /* 12 LSBit */
ConvertAirInterfaceID(CCH_CallingID, CallingID);
CallingID[7] = '\0';
/* Determine if the calling SRC ID is correct */
//if(HammingOk[0] && CrcOk[0] && HammingOk[1] && CrcOk[1])
if((CrcOk[0] || (HammingCorrectable[0][0] && HammingCorrectable[0][1])) &&
(CrcOk[1] || (HammingCorrectable[1][0] && HammingCorrectable[1][1])))
{
/* Save CCH data parameters */
state->dPMRVoiceFS2Frame.CallingIDOk = 1;
}
else
{
state->dPMRVoiceFS2Frame.CallingIDOk = 0;
}
/* BUGFIX : Copy in all case the SRC ID */
strcpy((char *)state->dPMRVoiceFS2Frame.CallingID, (char *)CallingID);
}
else
{
/* The dPMR source and destination ID are now invalid */
state->dPMRVoiceFS2Frame.CalledIDOk = 0;
state->dPMRVoiceFS2Frame.CallingIDOk = 0;
/* Unknown part of superframe => We suppose
* it is the next part of the previous frame received */
PartOfSuperFrame = opts->dPMR_next_part_of_superframe;
/* Set the next part of the superframe to receive */
if(opts->dPMR_next_part_of_superframe == 1)
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Supposed first part of the Super Frame\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* Set the next part as the second part */
opts->dPMR_next_part_of_superframe = 2;
}
else if(opts->dPMR_next_part_of_superframe == 2)
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Supposed second part of the Super Frame\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* Set the next part as the first part */
opts->dPMR_next_part_of_superframe = 1;
}
else
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Unknown part of the Super Frame\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* Unknown current part, set to 0 */
opts->dPMR_next_part_of_superframe = 0;
}
}
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
{
/* Display the color code */
//fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
}
else
{
/* Unknown color code, display "??" */
//fprintf(stderr, " | Color Code=?? ");
}
/* Display the destination ID (talk group - TG) */
//fprintf(stderr, "| TG=%s", CalledID);
if(state->dPMRVoiceFS2Frame.CalledIDOk)
{
fprintf(stderr, "| TG=%s", CalledID);
//strcpy (state->dpmr_target_id, CalledID); //HERE HERE
state->dpmr_target_id = CalledID;
//fprintf(stderr, " (CRC OK) ");
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
{
fprintf(stderr, " | Color Code=%02d ", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
}
}
else
{
//fprintf(stderr, " (CRC ERR) ");
}
/* Display the source ID */
//fprintf(stderr, "| Src=%s", CallingID);
if(state->dPMRVoiceFS2Frame.CallingIDOk)
{
fprintf(stderr, "| Src=%s", CallingID);
//strcpy (state->dpmr_caller_id, CallingID);
state->dpmr_caller_id = CallingID;
//fprintf(stderr, " (CRC OK) ");
}
else
{
fprintf(stderr, " (CRC ERR) ");
}
#endif /* (NB_OF_DPMR_VOICE_FRAME_TO_DECODE == 2) */
/* Test if the current frame is encrypted or not */
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
//if(HammingOk[i] && CrcOk[i])
if(HammingCorrectable[i][2] && CrcOk[i])
{
/* Unencrypted voice frame => Version = 0 (0b00) */
if(state->dPMRVoiceFS2Frame.Version[i] == 0x00)
{
opts->dPMR_curr_frame_is_encrypted = 0;
}
/* Encrypted voice frame => Version = 3 (0b11) */
else if(state->dPMRVoiceFS2Frame.Version[i] == 0x03)
{
opts->dPMR_curr_frame_is_encrypted = 1;
}
else
{
/* Unknown clear or encrypted voice frame status */
}
/* Valid encryption parameter found,
* exit the "for" loop */
break;
} /* End if(HammingCorrectable[i][2] && CrcOk[i]) */
}
if(opts->dPMR_curr_frame_is_encrypted) fprintf(stderr, "| Scrambler ");
/* Determine if the received frame is a voice frame, a voice frame + data
* or a data frame.
*
* See ETSI TS 102 658 chapter 5.0.5 "Communication Mode [BT]"
* for details
*/
VoiceFrameFlag = 0;
AttachedDataFlag = 0;
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
/* Search for voice frame
* Note : Due to error decoding, we parse all CCH
* Communication Mode parameters, if a voice parameter is
* found, the entire payload is considered as voice */
if((state->dPMRVoiceFS2Frame.CommunicationMode[i] == 0) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[i] == 1) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[i] == 5))
{
/* Voice frame detected */
VoiceFrameFlag = 1;
/* Check if the voice frame contains attached data */
if((state->dPMRVoiceFS2Frame.CommunicationMode[i] == 5) && state->dPMRVoiceFS2Frame.CCHDataCrcOk[i])
{
AttachedDataFlag = 1;
}
}
}
if(VoiceFrameFlag)
{
if(AttachedDataFlag) fprintf(stderr, "| Voice+Data ");
else fprintf(stderr, "| Voice ");
}
else
{
fprintf(stderr, "| Data ");
}
/* Demodulate and store AMBE sample only if the current superframe
* is a voice frame */
if(VoiceFrameFlag)
{
/* There is 4 AMBE voice sample per voice frame (= 8 per superframe) */
for(i = 0; i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4); i++)
{
/* Apply ECC 1 to the AMBE frames */
state->dPMRVoiceFS2Frame.errs1[i] = (unsigned int)mbe_eccAmbe3600x2450C0(ambe_fr[i]);
state->dPMRVoiceFS2Frame.errs2[i] = state->dPMRVoiceFS2Frame.errs1[i];
/* Demodulate the AMBE frames */
mbe_demodulateAmbe3600x2450Data(ambe_fr[i]);
/* Apply ECC 2 to the AMBE frames and get the 49 bit of the voice sample */
state->dPMRVoiceFS2Frame.errs2[i] += (unsigned int)mbe_eccAmbe3600x2450Data(ambe_fr[i], (char *)state->dPMRVoiceFS2Frame.AmbeBit[i]);
}
} /* End if(VoiceFrameFlag && !AttachedDataFlag) */
/* Check if the voice frame to play is encrypted */
if(opts->dPMR_curr_frame_is_encrypted)
{
/* Encryption is not supported in the public version */
ScramblerKey = 0;
}
else
{
/* The frame is unencrypted,
* so set the scrambler key to 0 */
ScramblerKey = 0;
}
/* Play only voice frame */
if(VoiceFrameFlag)
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Voice frame to play\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
/* There is 4 AMBE voice sample per voice frame (so 2 x 4 = 8 per superframe) */
for(i = 0; i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4); i++)
{
errs = (uint32_t*)&(state->dPMRVoiceFS2Frame.errs1[i]);
errs2 = (uint32_t*)&(state->dPMRVoiceFS2Frame.errs2[i]);
state->errs = state->dPMRVoiceFS2Frame.errs1[i];
state->errs2 = state->dPMRVoiceFS2Frame.errs2[i];
//sounds like choppy shit, but .amb file playback is acceptable, so investigate why this doesn't work properly
mbe_processAmbe2450Dataf (state->audio_out_temp_buf, (int *)errs, (int *)errs2, state->err_str,
(char *)state->dPMRVoiceFS2Frame.AmbeBit[i],
state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
//mbe_processAmbe2450Data ((short *) state->audio_out_temp_buf_p, (int *)errs, (int *)errs2, state->err_str,
// (char *)state->dPMRVoiceFS2Frame.AmbeBit[i],
// state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
if (opts->mbe_out_f != NULL)
{
saveAmbe2450Data (opts, state, (char *)state->dPMRVoiceFS2Frame.AmbeBit[i]);
}
if (opts->errorbars == 1)
{
fprintf(stderr, "%s", state->err_str);
}
state->debug_audio_errors += *errs2;
processAudio(opts, state);
if (opts->wav_out_f != NULL)
{
writeSynthesizedVoice (opts, state);
}
if (opts->audio_out == 1)
{
/* Play the AMBE Frames */
playSynthesizedVoice (opts, state);
}
} /* End for(i = 0; i < (NB_OF_DPMR_VOICE_FRAME_TO_DECODE * 4); i++) */
} /* End if(VoiceFrameFlag) */
else
{
#ifdef dPMR_PRINT_DEBUG_INFO
fprintf(stderr, "Data frame, don't play it !\n");
#endif /* dPMR_PRINT_DEBUG_INFO */
}
if (opts->errorbars == 1)
{
fprintf(stderr, "\n");
}
#ifdef dPMR_PRINT_DEBUG_INFO
/* Display the CCH content */
for(i = 0; i < NB_OF_DPMR_VOICE_FRAME_TO_DECODE; i++)
{
fprintf(stderr, "i = %u - ", i);
fprintf(stderr, "Comm Mode = %01u - ", state->dPMRVoiceFS2Frame.CommunicationMode[i]);
fprintf(stderr, "Version = %01u - ", state->dPMRVoiceFS2Frame.Version[i]);
fprintf(stderr, "Comms Format = %01u - ", state->dPMRVoiceFS2Frame.CommsFormat[i]);
fprintf(stderr, "Emergency = %01u - ", state->dPMRVoiceFS2Frame.EmergencyPriority[i]);
fprintf(stderr, "Reserved = %01u - ", state->dPMRVoiceFS2Frame.Reserved[i]);
fprintf(stderr, "Slow Data = 0x%05X - ", state->dPMRVoiceFS2Frame.SlowData[i]);
if(HammingOk[i] && CrcOk[i]) fprintf(stderr, "Valid");
else fprintf(stderr, "CRC ERROR");
fprintf(stderr, "\n");
}
#endif /* dPMR_PRINT_DEBUG_INFO */
/* Print sPMR frame (if needed) */
//dPMRVoiceFrameProcess(opts, state); //HERE HERE disabled to build
} /* End processdPMRvoice() */
/* Scrambler used for dPMR transmission (different of the
* voice encryption scrambler), see ETSI TS 102 658 chapter
* 7.3 for the polynomial description.
* It is a X^9 + X^5 + 1 polynomial. */
void ScrambledPMRBit(uint32_t * LfsrValue, uint8_t * BufferIn, uint8_t * BufferOut, uint32_t NbOfBitToScramble)
{
uint8_t S[9] = {0};
uint32_t i;
uint8_t Temp;
uint32_t LFSRValue;
LFSRValue = *LfsrValue;
/* Load the initial LFSR value */
for(i = 0; i < 9; i++)
{
S[i] = LFSRValue & 1;
LFSRValue >>= 1;
}
/* There are 72 bit to encrypt for voice and 288 bit for data */
for(i = 0; i < NbOfBitToScramble; i++)
{
BufferOut[i] = (BufferIn[i] ^ S[0]) & 0x01;
/* Shift registers */
Temp = S[4] ^ S[0];
S[0] = S[1];
S[1] = S[2];
S[2] = S[3];
S[3] = S[4];
S[4] = S[5];
S[5] = S[6];
S[6] = S[7];
S[7] = S[8];
S[8] = Temp;
}
/* Save the final LFSR value */
LFSRValue = 0;
for(i = 9; i > 0; i--)
{
LFSRValue <<= 1;
LFSRValue |= S[i - 1] & 1;
}
*LfsrValue = LFSRValue;
} /* End ScrambleDPmrBit() */
/* Scrambler used for dPMR encryption / decryption,
* see ETSI TS 102 658 chapter 7.3 for the
* polynomial description.
* It is a X^9 + X^5 + 1 polynomial. */
void DeInterleave6x12DPmrBit(uint8_t * BufferIn, uint8_t * BufferOut)
{
uint8_t Matrix[12][6] = {0};
uint32_t i, j, k;
/* Step 1 : Filling the 12 x 6 bit matrix */
k = 0;
for(i = 0; i < 12; i++)
{
for(j = 0; j < 6; j++)
{
Matrix[i][j] = BufferIn[k++];
}
}
/* Step 2 : Filling the output buffer with deinterleaved data */
k = 0;
for(j = 0; j < 6; j++)
{
for(i = 0; i < 12; i++)
{
BufferOut[k++] = Matrix[i][j];
}
}
} /* End DeInterleave6x12DPmrBit() */
/* CRC 7 bit computation with the following
* polynomial : X^7 + X^3 + 1 */
uint8_t CRC7BitdPMR(uint8_t * BufferIn, uint32_t BitLength)
{
uint8_t ShiftRegister = 0x00; /* All bit to '0' (7 LSBit only used) */
uint8_t Polynome = 0x09; /* X^7 + X^3 + 1 */
uint32_t i;
for(i = 0; i < BitLength; i++)
{
if(((ShiftRegister >> 6) & 1) ^ BufferIn[i])
{
ShiftRegister = ((ShiftRegister << 1) ^ Polynome) & 0x7F;
}
else
{
ShiftRegister = (ShiftRegister << 1) & 0x7F;
}
}
return ShiftRegister;
} /* End CRC7BitdPMR() */
/* CRC 8 bit computation with the following
* polynomial : X^8 + X^2 + X + 1 */
uint8_t CRC8BitdPMR(uint8_t * BufferIn, uint32_t BitLength)
{
uint8_t ShiftRegister = 0xFF; /* All bit to '1' */
uint8_t Polynome = 0x07; /* X^7 + X^3 + 1 */
uint32_t i;
for(i = 0; i < BitLength; i++)
{
if(((ShiftRegister >> 7) & 1) ^ BufferIn[i])
{
ShiftRegister = ((ShiftRegister << 1) ^ Polynome) & 0xFF;
}
else
{
ShiftRegister = (ShiftRegister << 1) & 0xFF;
}
}
return ShiftRegister;
} /* End CRC8BitdPMR() */
/* Convert an air interface identifier (AI ID) into
* a 7 ASCII digit string.
*
* See dPMR standard chapter A.1.2.1.1.6
* "Mapping of dialled strings to the AI address space" */
void ConvertAirInterfaceID(uint32_t AI_ID, uint8_t ID[8])
{
uint32_t AI_ID_Temp = AI_ID;
uint32_t Digit;
/* 1st digit */
Digit = AI_ID_Temp / 1464100;
AI_ID_Temp = AI_ID_Temp % 1464100;
if(Digit == 10) ID[0] = '*';
else ID[0] = Digit + '0';
/* 2nd digit */
Digit = AI_ID_Temp / 146410;
AI_ID_Temp = AI_ID_Temp % 146410;
if(Digit == 10) ID[1] = '*';
else ID[1] = Digit + '0';
/* 3rd digit */
Digit = AI_ID_Temp / 14641;
AI_ID_Temp = AI_ID_Temp % 14641;
if(Digit == 10) ID[2] = '*';
else ID[2] = Digit + '0';
/* 4th digit */
Digit = AI_ID_Temp / 1331;
AI_ID_Temp = AI_ID_Temp % 1331;
if(Digit == 10) ID[3] = '*';
else ID[3] = Digit + '0';
/* 5th digit */
Digit = AI_ID_Temp / 121;
AI_ID_Temp = AI_ID_Temp % 121;
if(Digit == 10) ID[4] = '*';
else ID[4] = Digit + '0';
/* 6th digit */
Digit = AI_ID_Temp / 11;
AI_ID_Temp = AI_ID_Temp % 11;
if(Digit == 10) ID[5] = '*';
else ID[5] = Digit + '0';
/* 7th digit */
Digit = AI_ID_Temp;
if(Digit == 10) ID[6] = '*';
else ID[6] = Digit + '0';
/* Add the "end of string" */
ID[7] = '\0';
} /* End convertAirInterfaceID() */
/* End of file */

View File

@@ -72,7 +72,8 @@ saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
fprintf(stderr, "\n");
}
for (i = 0; i < 6; i++)
//for (i = 0; i < 6; i++)
for (i = 0; i < 7; i++)
{
b = 0;
@@ -103,12 +104,17 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
{
int i, j, k;
unsigned char b;
unsigned char b, x;
state->errs2 = fgetc (opts->mbe_in_f);
state->errs = state->errs2;
k = 0;
if (opts->payload == 1) //make opt variable later on to toggle this
{
fprintf(stderr, "\n");
}
for (i = 0; i < 11; i++)
{
b = fgetc (opts->mbe_in_f);
@@ -119,10 +125,24 @@ readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
for (j = 0; j < 8; j++)
{
imbe_d[k] = (b & 128) >> 7;
x = x << 1;
x |= ((b & 0x80) >> 7);
b = b << 1;
b = b & 255;
k++;
}
//new printout on reading MBE files back in
if (opts->payload == 1) //make opt variable later on to toggle this
{
fprintf (stderr, "[%02X] ", x);
}
//
}
if (opts->payload == 1)
{
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2); //not sure that errs here are legit values
}
return (0);
}
@@ -132,13 +152,18 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
{
int i, j, k;
unsigned char b;
unsigned char b, x;
state->errs2 = fgetc (opts->mbe_in_f);
state->errs = state->errs2;
k = 0;
for (i = 0; i < 6; i++)
if (opts->payload == 1) //make opt variable later on to toggle this
{
fprintf(stderr, "\n");
}
//for (i = 0; i < 6; i++)
for (i = 0; i < 7; i++)
{
b = fgetc (opts->mbe_in_f);
if (feof (opts->mbe_in_f))
@@ -148,10 +173,22 @@ readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
for (j = 0; j < 8; j++)
{
ambe_d[k] = (b & 128) >> 7;
x = x << 1;
x |= ((b & 0x80) >> 7);
b = b << 1;
b = b & 255;
k++;
}
if (opts->payload == 1) //make opt variable later on to toggle this
{
fprintf (stderr, "[%02X] ", x);
}
}
if (opts->payload == 1)
{
fprintf(stderr, " err = [%X] [%X] ", state->errs, state->errs2);
}
b = fgetc (opts->mbe_in_f);
ambe_d[48] = (b & 1);
@@ -247,7 +284,7 @@ closeMbeOutFile (dsd_opts * opts, dsd_state * state)
{
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);

View File

@@ -244,6 +244,50 @@ processFrame (dsd_opts * opts, dsd_state * state)
processProVoice (opts, state);
return;
}
//LEH dPMR
else if ((state->synctype == 20) || (state->synctype == 24))
{
/* dPMR Frame Sync 1 */
fprintf(stderr, "dPMR Frame sync 1 ");
}
else if ((state->synctype == 21) || (state->synctype == 25))
{
/* dPMR Frame Sync 2 */
fprintf(stderr, "dPMR Frame sync 2 ");
{
//state->rf_mod = GFSK_MODE;
state->nac = 0;
state->lastsrc = 0;
state->lasttg = 0;
if (opts->errorbars == 1)
{
if (opts->verbose > 0)
{
level = (int) state->max / 164;
fprintf(stderr, "inlvl: %2i%% ", level);
}
}
state->nac = 0;
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
{
openMbeOutFile (opts, state);
}
sprintf(state->fsubtype, " VOICE ");
processdPMRvoice (opts, state);
return;
}
}
else if ((state->synctype == 22) || (state->synctype == 26))
{
/* dPMR Frame Sync 3 */
fprintf(stderr, "dPMR Frame sync 3 ");
}
else if ((state->synctype == 23) || (state->synctype == 27))
{
/* dPMR Frame Sync 4 */
fprintf(stderr, "dPMR Frame sync 4 ");
}
//LEH dPMR
else
{
// Read the NAC, 12 bits

View File

@@ -143,11 +143,22 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
* 17 = -NXDN (inverted data frame)
* 18 = +D-STAR_HD
* 19 = -D-STAR_HD
* 20 = +dPMR Frame Sync 1
* 21 = +dPMR Frame Sync 2
* 22 = +dPMR Frame Sync 3
* 23 = +dPMR Frame Sync 4
* 24 = -dPMR Frame Sync 1
* 25 = -dPMR Frame Sync 2
* 26 = -dPMR Frame Sync 3
* 27 = -dPMR Frame Sync 4
* 28 = +NXDN (sync only)
* 29 = -NXDN (sync only
*/
int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt;
char synctest[25];
char synctest12[13]; //LEH DPMR
char synctest18[19];
char synctest32[33];
char modulation[8];
@@ -195,7 +206,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
playRawAudio(opts, state); //this is on line 21 in dsd_audio.c
}
*/
/*
if (opts->reset_state == 1 && state->carrier == 0)
{
@@ -512,6 +523,8 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
}
}
//old style for DMR
/*
if (opts->frame_dmr == 1)
{
if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0) )//try this
@@ -586,6 +599,734 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
}
}
}
*/
//LEH dPMR
if(opts->frame_dpmr == 1)
{
strncpy(synctest, (synctest_p - 23), 24);
strncpy(synctest12, (synctest_p - 11), 12);
if(strcmp(synctest, DPMR_FRAME_SYNC_1) == 0)
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_1\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
/* The next part of the superframe will normally be the first part */
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 20;
return (20);
}
else
{
state->lastsynctype = 20;
}
} /* End if (opts->inverted_dpmr == 0) */
}
else if(strcmp(synctest12, DPMR_FRAME_SYNC_2) == 0)
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_2\n"); // TODO : To be removed
// TODO : Modif 2019-01-04
//if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
// (state->lastsynctype == 22) || (state->lastsynctype == 23))
//{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 21;
return (21);
// TODO : Modif 2019-01-04
//}
//else
//{
// state->lastsynctype = 21;
//}
}
}
else if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_3\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
/* The next part of the superframe will normally be the first part */
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 22;
return (22);
}
else
{
state->lastsynctype = 22;
}
}
}
if(strcmp(synctest, DPMR_FRAME_SYNC_4) == 0)
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_4\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
/* The next part of the superframe will normally be the first part */
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 23;
return (23);
}
else
{
state->lastsynctype = 23;
}
}
}
else if(strcmp(synctest, INV_DPMR_FRAME_SYNC_1) == 0)
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_1\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 24;
return (24);
}
else
{
state->lastsynctype = 24;
}
}
}
else if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_2) == 0)
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_2\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 25;
return (25);
}
else
{
state->lastsynctype = 25;
}
}
}
else if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_3\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 26;
return (26);
}
else
{
state->lastsynctype = 26;
}
}
}
if(strcmp(synctest, INV_DPMR_FRAME_SYNC_4) == 0)
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_4\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 27;
return (27);
}
else
{
state->lastsynctype = 27;
}
}
}
else
{
/* No dPMR frame sync detected */
}
} /* End if(opts->frame_dpmr == 1) */
//
//LEH dPMR
/* //testing frame syncs here for better performance
if(opts->frame_dpmr == 1)
{
strncpy(synctest, (synctest_p - 23), 24);
strncpy(synctest12, (synctest_p - 11), 12);
//if(strcmp(synctest, DPMR_FRAME_SYNC_1) == 0)
if (strncmperr (synctest, DPMR_FRAME_SYNC_1, 24, 1) == 0 ) //24 bits on frame 1 and 4, 12 on 2 and 3?
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_1\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
//The next part of the superframe will normally be the first part
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 20;
return (20);
}
else
{
state->lastsynctype = 20;
}
} //End if (opts->inverted_dpmr == 0)
}
//else if(strcmp(synctest12, DPMR_FRAME_SYNC_2) == 0)
if (strncmperr (synctest12, DPMR_FRAME_SYNC_2, 12, 1) == 0 ) //char synctest12[13] ??
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_2\n"); // TODO : To be removed
// TODO : Modif 2019-01-04
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 21;
return (21);
// TODO : Modif 2019-01-04
}
else
{
state->lastsynctype = 21;
}
}
}
//else if(strcmp(synctest12, DPMR_FRAME_SYNC_3) == 0)
if (strncmperr (synctest12, DPMR_FRAME_SYNC_3, 12, 1) == 0 ) //char synctest12[13] ??
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_3\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
//The next part of the superframe will normally be the first part//
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 22;
return (22);
}
else
{
state->lastsynctype = 22;
}
}
}
//if(strcmp(synctest, DPMR_FRAME_SYNC_4) == 0)
if (strncmperr (synctest, DPMR_FRAME_SYNC_4, 24, 1) == 0 ) //if, or else if? original is else if
{
if (opts->inverted_dpmr == 0)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_4\n"); // TODO : To be removed
if ((state->lastsynctype == 20) || (state->lastsynctype == 21) ||
(state->lastsynctype == 22) || (state->lastsynctype == 23))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +dPMR ", synctest_pos + 1, modulation);
}
//The next part of the superframe will normally be the first part
//opts->dPMR_next_part_of_superframe = 1;
state->lastsynctype = 23;
return (23);
}
else
{
state->lastsynctype = 23;
}
}
}
//else if(strcmp(synctest, INV_DPMR_FRAME_SYNC_1) == 0)
//else if (strncmperr (synctest12, INV_DPMR_FRAME_SYNC_1, 12, 1) == 0 )
if (strncmperr (synctest, INV_DPMR_FRAME_SYNC_1, 24, 1) == 0 ) //if, or else if
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_1\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 24;
return (24);
}
else
{
state->lastsynctype = 24;
}
}
}
//else if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_2) == 0)
if (strncmperr (synctest12, INV_DPMR_FRAME_SYNC_2, 12, 1) == 0 )
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "DPMR_FRAME_SYNC_2\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 25;
return (25);
}
else
{
state->lastsynctype = 25;
}
}
}
//else if(strcmp(synctest12, INV_DPMR_FRAME_SYNC_3) == 0)
if (strncmperr (synctest12, INV_DPMR_FRAME_SYNC_3, 12, 1) == 0 )
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_3\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 26;
return (26);
}
else
{
state->lastsynctype = 26;
}
}
}
//if(strcmp(synctest, INV_DPMR_FRAME_SYNC_4) == 0) //if, or else if
if (strncmperr (synctest, INV_DPMR_FRAME_SYNC_4, 24, 1) == 0 )
{
if (opts->inverted_dpmr)
{
//fprintf(stderr, "INV_DPMR_FRAME_SYNC_4\n"); // TODO : To be removed
if ((state->lastsynctype == 24) || (state->lastsynctype == 25) ||
(state->lastsynctype == 26) || (state->lastsynctype == 27))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
sprintf(state->ftype, " dPMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -dPMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 27;
return (27);
}
else
{
state->lastsynctype = 27;
}
}
}
else
{
//No dPMR frame sync detected
}
} //End if(opts->frame_dpmr == 1)
*/
//LEH DMR Sync
if (opts->frame_dmr == 1)
{
if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
state->directmode = 0;
if (opts->inverted_dmr == 0)
{
// data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 10;
return (10);
}
else
{
// inverted voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 11)
{
state->firstframe = 1;
}
state->lastsynctype = 11;
return (11);
}
}
if(strcmp (synctest, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
state->currentslot = 0;
state->directmode = 1; //Direct mode
if (opts->inverted_dmr == 0)
{
// data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 10;
return (10);
}
else
{
// inverted voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 11)
{
state->firstframe = 1;
}
state->lastsynctype = 11;
return (11);
}
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) */
if(strcmp (synctest, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + (lmax)) / 2;
state->min = ((state->min) + (lmin)) / 2;
state->currentslot = 1;
state->directmode = 1; //Direct mode
if (opts->inverted_dmr == 0)
{
// data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 10;
return (10);
}
else
{
// inverted voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 11)
{
state->firstframe = 1;
}
state->lastsynctype = 11;
return (11);
}
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) */
if((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0))
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->directmode = 0;
if (opts->inverted_dmr == 0)
{
// voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 12)
{
state->firstframe = 1;
}
state->lastsynctype = 12;
return (12);
}
else
{
// inverted data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 13;
return (13);
}
}
if(strcmp (synctest, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->currentslot = 0;
state->directmode = 1; //Direct mode
if (opts->inverted_dmr == 0)
{
// voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 12)
{
state->firstframe = 1;
}
state->lastsynctype = 12;
return (12);
}
else
{
// inverted data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 13;
return (13);
}
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) */
if(strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
{
state->carrier = 1;
state->offset = synctest_pos;
state->max = ((state->max) + lmax) / 2;
state->min = ((state->min) + lmin) / 2;
state->currentslot = 1;
state->directmode = 1; //Direct mode
if (opts->inverted_dmr == 0)
{
// voice frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
}
if (state->lastsynctype != 12)
{
state->firstframe = 1;
}
state->lastsynctype = 12;
return (12);
}
else
{
// inverted data frame
sprintf(state->ftype, " DMR ");
if (opts->errorbars == 1)
{
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
}
state->lastsynctype = 13;
return (13);
}
} //End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
} //End if (opts->frame_dmr == 1)
//end LEH DMR Sync
if (opts->frame_provoice == 1)
{
strncpy (synctest32, (synctest_p - 31), 32);

View File

@@ -168,6 +168,7 @@ initOpts (dsd_opts * opts)
opts->frame_nxdn48 = 0;
opts->frame_nxdn96 = 0;
opts->frame_dmr = 1;
opts->frame_dpmr = 0; //borrow from LEH
opts->frame_provoice = 0;
opts->mod_c4fm = 1;
opts->mod_qpsk = 1;
@@ -190,16 +191,19 @@ initOpts (dsd_opts * opts)
opts->rtl_bandwidth = 12; //changed recommended default to 12, 24 for ProVoice
opts->pulse_raw_rate_in = 48000;
opts->pulse_raw_rate_out = 48000; //doing tests with 2 channels at 24000 for 48000 audio default in pulse
opts->pulse_digi_rate_in = 24000;
opts->pulse_digi_rate_in = 48000;
opts->pulse_digi_rate_out = 24000; //need to copy this to rtl type in and change rate out to 8000
opts->pulse_raw_in_channels = 1;
opts->pulse_raw_out_channels = 1;
opts->pulse_digi_in_channels = 2;
opts->pulse_digi_in_channels = 1; //2
opts->pulse_digi_out_channels = 2;
opts->pulse_flush = 1; //set 0 to flush, 1 for flushed
opts->use_ncurses_terminal = 0; //ncurses terminal disabled by default, call with -N
opts->payload = 0; //initialize with 0 so can pass == 0 arguments
opts->EncryptionMode = MODE_UNENCRYPTED;
opts->inverted_dpmr = 0;
}
void
@@ -297,6 +301,10 @@ initState (dsd_state * state)
state->nxdn_last_ran = -1;
state->nxdn_last_rid = 0;
state->dpmr_color_code = -1;
state->dpmr_caller_id = 0;
state->dpmr_target_id = 0;
#ifdef TRACE_DSD
state->debug_sample_index = 0;
state->debug_label_file = NULL;
@@ -357,11 +365,12 @@ usage ()
fprintf (stderr," -fa Auto-detect frame type (default)\n");
fprintf (stderr," -f1 Decode only P25 Phase 1\n");
fprintf (stderr," -fd Decode only D-STAR\n");
fprintf (stderr," -fr Decode only DMR/MOTOTRBO\n");
fprintf (stderr," -fx Decode only X2-TDMA\n");
fprintf (stderr," -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
fprintf (stderr," -fn Decode only NXDN96* (12.5 kHz)\n");
fprintf (stderr," -fp Decode only ProVoice*\n");
fprintf (stderr," -fr Decode only DMR/MOTOTRBO\n");
fprintf (stderr," -fx Decode only X2-TDMA\n");
fprintf (stderr," -fm Decode only dPMR*\n");
fprintf (stderr," -l Disable DMR/MOTOTRBO and NXDN input filtering\n");
fprintf (stderr," -ma Auto-select modulation optimizations (default)\n");
fprintf (stderr," -mc Use only C4FM modulation optimizations\n");
@@ -371,6 +380,7 @@ usage ()
fprintf (stderr," -u <num> Unvoiced speech quality (default=3)\n");
fprintf (stderr," -xx Expect non-inverted X2-TDMA signal\n");
fprintf (stderr," -xr Expect inverted DMR/MOTOTRBO signal\n");
fprintf (stderr," -xd Expect inverted ICOM dPMR signal\n"); //still need to do this
fprintf (stderr,"\n");
fprintf (stderr," * denotes frame types that cannot be auto-detected.\n");
fprintf (stderr,"\n");
@@ -619,6 +629,8 @@ main (int argc, char **argv)
initOpts (&opts);
initState (&state);
InitAllFecFunction(); //HERE
exitflag = 0;
signal (SIGINT, sigfun);
@@ -807,6 +819,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0; //turn it on, doesn't work due to symbol rate difference
opts.frame_nxdn96 = 0; //causes false positives, leave on 0
opts.frame_dmr = 1;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0; //turn it on, doesn't work due to symbol rate difference
}
else if (optarg[0] == 'd')
@@ -817,6 +830,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
fprintf (stderr,"Decoding only D-STAR frames.\n");
}
@@ -828,6 +842,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
fprintf (stderr,"Decoding only X2-TDMA frames.\n");
}
@@ -839,6 +854,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 1;
state.samplesPerSymbol = 5;
state.symbolCenter = 2;
@@ -858,6 +874,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
opts.mod_gfsk = 0;
opts.mod_c4fm = 1; //Phase 1 only uses C4FM, right?
@@ -873,6 +890,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 1;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
//I think I've got it to decode on proper modulation now c4fm, not really sure what the difference is in DSD, seems to work either way for some reason
state.samplesPerSymbol = 20;
@@ -894,6 +912,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 1;
opts.frame_dmr = 0;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
opts.mod_c4fm = 1; //was 0
opts.mod_qpsk = 0;
@@ -910,6 +929,7 @@ main (int argc, char **argv)
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 1;
opts.frame_dpmr = 0; //borrow from LEH
opts.frame_provoice = 0;
opts.mod_c4fm = 1; //just a test
opts.mod_qpsk = 0;
@@ -917,6 +937,32 @@ main (int argc, char **argv)
state.rf_mod = 0; //
fprintf (stderr,"Decoding only DMR/MOTOTRBO frames.\n");
}
else if (optarg[0] == 'm')
{
opts.frame_dstar = 0;
opts.frame_x2tdma = 0;
opts.frame_p25p1 = 0;
opts.frame_nxdn48 = 0;
opts.frame_nxdn96 = 0;
opts.frame_dmr = 0;
opts.frame_provoice = 0;
opts.frame_dpmr = 1;
state.samplesPerSymbol = 20; //same as NXDN48 - 20
state.symbolCenter = 10; //same as NXDN48 - 10
opts.mod_c4fm = 1;
opts.mod_qpsk = 0;
opts.mod_gfsk = 0;
state.rf_mod = 0;
//opts.pulse_digi_rate_in = 48000;
//opts.pulse_digi_rate_out = 48000; //need to copy this to rtl type in and change rate out to 8000
//opts.pulse_digi_in_channels = 1;
//opts.pulse_digi_out_channels = 1;
//opts.inverted_dpmr = 1;
fprintf(stderr, "Setting symbol rate to 2400 / second\n");
//fprintf(stderr, "Enabling only GFSK modulation optimizations.\n");
fprintf(stderr, "Enabling only C4FM modulation optimizations.\n");
fprintf(stderr, "Decoding only dPMR (4800 baud frames).\n");
}
break;
case 'm':
if (optarg[0] == 'a')
@@ -974,6 +1020,11 @@ main (int argc, char **argv)
opts.inverted_dmr = 1;
fprintf (stderr,"Expecting inverted DMR/MOTOTRBO signals.\n");
}
else if (optarg[0] == 'd')
{
opts.inverted_dpmr = 1;
fprintf (stderr, "Expecting inverted ICOM dPMR signals.\n");
}
break;
case 'A':
sscanf (optarg, "%i", &opts.mod_threshold);

View File

@@ -36,7 +36,7 @@ int rn; //last ran
int nc; //nac
int src; //last rid? double?
int lls = -1; //last last sync type
int dcc = 0; //initialize with 0 to prevent core dump
int dcc = -1; //initialize with 0 to prevent core dump
int i = 0;
char * s0last = " ";
char * s1last = " ";
@@ -53,7 +53,7 @@ char * FM_bannerN[9] = {
"https://github.com/lwvmobile/dsd-fme/tree/pulseaudio "
};
char * SyncTypes[20] = {
char * SyncTypes[30] = {
"+P25P1",
"-P25P1",
"+X2TDMA DATA",
@@ -73,7 +73,15 @@ char * SyncTypes[20] = {
"+NXDN DATA", //16
"-NXDN DATA", //17
"+DSTAR HD",
"-DSTAR HD"
"-DSTAR HD",
"+dPMR",
"+dPMR",
"+dPMR",
"+dPMR",
"-dPMR",
"-dPMR",
"-dPMR",
"-dPMR"
};
@@ -187,7 +195,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//if (state->dmr_color_code != dcc && (lls == 11 || lls == 13 || lls == 10 || lls == 12) ) //DMR Voice + last two is data
//if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR
if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 12 || lls == 13) ) //DMR
if ( (call_matrix[9][4] != dcc || call_matrix[9][2] != rd) && (lls == 12 || lls == 13) ) //DMR, needs work
{
//dcc = state->dmr_color_code;
for (short int k = 0; k < 9; k++)
@@ -302,19 +310,25 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
rn = state->nxdn_last_ran;
}
if (state->dmr_color_code > 0 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data?
//if (state->dmr_color_code > 0 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data?
//if (state->color_code > -1 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data?
if (state->color_code_ok && (lls == 12 || lls == 13) ) //DMR, needs work
{
dcc = state->dmr_color_code;
//dcc = state->color_code;
}
if (state->lastsrc > 0 && (lls == 12 || lls == 13))
if (state->lastsrc > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1
{
rd = state->lastsrc;
opts->p25enc = 0;
}
if (state->lasttg > 0 && (lls == 12 || lls == 13))
if (state->lasttg > 0 && (lls == 12 || lls == 13 || lls == 0 || lls == 1)) //DMR Voice and P25P1
{
tg = state->lasttg;
opts->p25enc = 0;
}
//if (state->lastsynctype == 8 || state->lastsynctype == 9 || state->lastsynctype == 16 || state->lastsynctype == 17) //change this to NXDN syncs later on
@@ -326,12 +340,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
//printw ("Error?: [%i] [%i] \n", state->errs, state->errs2); //what are these?
/* //wasn't we already doing this twice
if (state->lasttg > 0 && state->lastsrc > 0)
{
tg = state->lasttg;
rd = state->lastsrc;
}
*/
if (state->nac > 0)
{
nc = state->nac;
@@ -358,7 +373,35 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//if (state->lastsynctype == 12 || state->lastsynctype == 13) //DMR Voice Types
if (lls == 12 || lls == 13) //DMR Voice Types
{
printw ("| DCC: [%i]\n", dcc);
//printw ("| DCC: [%i] FID: [%02X]\n", dcc, state->dmr_fid);
printw ("| DCC: [%i] FID: [%02X] SOP: [%X] \n", dcc, state->dmr_fid, state->dmr_so);
printw ("| TID: [%i] RID: [%i]", tg, rd);
if(state->dmr_so & 0x80) //& apparently is same as ==
{
attron(COLOR_PAIR(2));
printw (" **Emergency** ");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
if(state->dmr_so & 0x40)
{
attron(COLOR_PAIR(2));
printw (" **ENC** ");
//printw ("0x%X", state->payload_algid);
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
//opts->p25enc = 1; //just testing for now
}
if(state->dmr_so & 0x30)
{
attron(COLOR_PAIR(2));
printw (" **Private Call** ");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
printw("\n");
//printw ("%s ", state->slot0light);
printw ("| SLOT 0 ");
if (state->currentslot == 0) //find out how to tell when slot0 has voice
@@ -380,9 +423,39 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
//if (state->lastsynctype == 10 || state->lastsynctype == 11) //DMR Data Types
if (lls == 10 || lls == 11) //DMR Data Types
if (lls == 10 || lls == 11 ) //DMR Data Types
{
printw ("| DCC: [%i]\n", dcc);
//printw ("| DCC: [%i]\n", dcc);
printw ("| DCC: [%i] FID: [%02X] SOP: [%X] \n", dcc, state->dmr_fid, state->dmr_so);
printw ("| TID: [%i] RID: [%i]", tg, rd);
//does this need to be in DATA type?
/*
if(state->dmr_so & 0x80)
{
attron(COLOR_PAIR(2));
printw (" **Emergency** ");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
if(state->dmr_so & 0x40)
{
attron(COLOR_PAIR(2));
printw (" **ENC** ");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
if(state->dmr_so & 0x30)
{
attron(COLOR_PAIR(2));
printw (" **Private Call** ");
attroff(COLOR_PAIR(2));
attron(COLOR_PAIR(3));
}
*/
printw("\n");
//printw ("%s ", state->slot0light);
printw ("| SLOT 0 ");
if (state->currentslot == 0) //find out how to tell when slot0 has voice
@@ -406,6 +479,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
}
printw ("%s \n", s1last);
}
//dPMR
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27)
{
printw ("| DCC: [%i] ", state->dpmr_color_code);
printw ("TID: [%s] RID: [%s] \n", state->dpmr_target_id, state->dpmr_caller_id);
}
if (lls != -1) //is there a synctype 0?
{
printw ("| %s \n", SyncTypes[lls]);

1448
src/fec.c Normal file

File diff suppressed because it is too large Load Diff

316
src/rs-12-9.c Normal file
View File

@@ -0,0 +1,316 @@
/*
* This file is part of dmrshark.
*
* dmrshark is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dmrshark is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dmrshark. If not, see <http://www.gnu.org/licenses/>.
**/
// Reed-Solomon (12,9) error-correction coding.
//
// As there are 3 checksum bytes, we can only correct 1 erroneous byte.
//
// Based on the code by Henry Minsky (hqm@alum.mit.edu), http://rscode.sourceforge.net
// Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location are
// from Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205.
//#include DEFAULTCONFIG
#include "dsd.h"
//#include <libs/daemon/console.h>
#include <stdio.h>
#include <string.h>
typedef struct {
uint8_t error_locations[256];
uint8_t errors_num;
} rs_12_9_roots_t;
// See DMR AI. spec. page 138.
static uint8_t rs_12_9_galois_exp_table[256] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 0xE8, 0xCD, 0x87, 0x13, 0x26,
0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0,
0x9D, 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 0xEE, 0xC1, 0x9F, 0x23,
0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1,
0x5F, 0xBE, 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2,
0xD9, 0xAF, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 0x67, 0xCE,
0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC,
0x85, 0x17, 0x2E, 0x5C, 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 0x54,
0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73,
0xE6, 0xD1, 0xBF, 0x63, 0xC6, 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF,
0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 0xDC, 0xA5, 0x57, 0xAE, 0x41,
0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6,
0x51, 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 0xAC, 0x45, 0x8A, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16,
0x2C, 0x58, 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 0x47, 0x8E, 0x01,
};
// See DMR AI. spec. page 138.
static uint8_t rs_12_9_galois_log_table[256] = {
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75,
4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69,
29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166,
6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64,
30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87,
7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97,
242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162,
31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246,
108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90,
203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
};
static uint8_t rs_12_9_galois_exp_table_get(uint8_t pos) {
return rs_12_9_galois_exp_table[pos];
}
static uint8_t rs_12_9_galois_multiplication(uint8_t a, uint8_t b) {
if (a == 0 || b == 0)
return 0;
return rs_12_9_galois_exp_table[(rs_12_9_galois_log_table[a] + rs_12_9_galois_log_table[b]) % 255];
}
static uint8_t rs_12_9_galois_inv(uint8_t elt) {
return rs_12_9_galois_exp_table[255-rs_12_9_galois_log_table[elt]];
}
// Multiply by z (shift right by 1).
static void rs_12_9_multiply_poly_z(rs_12_9_poly_t *poly) {
uint8_t i;
for (i = RS_12_9_POLY_MAXDEG-1; i > 0; i--)
poly->data[i] = poly->data[i-1];
poly->data[0] = 0;
}
static void rs_12_9_multiplicate_polys(uint8_t dst[], rs_12_9_poly_t *p1, rs_12_9_poly_t *p2) {
uint8_t i;
int8_t j;
int8_t tmp1[RS_12_9_POLY_MAXDEG*2];
for (i = 0; i < RS_12_9_POLY_MAXDEG*2; i++)
dst[i] = 0;
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++) {
for(j = RS_12_9_POLY_MAXDEG; j < (RS_12_9_POLY_MAXDEG*2); j++)
tmp1[j] = 0;
// Scale tmp1 by p1[i]
for(j = 0; j < RS_12_9_POLY_MAXDEG; j++)
tmp1[j] = rs_12_9_galois_multiplication(p2->data[j], p1->data[i]);
// Shift (multiply) tmp1 right by i
for (j = (RS_12_9_POLY_MAXDEG*2)-1; j >= i; j--)
tmp1[j] = tmp1[j-i];
for (j = 0; j < i; j++)
tmp1[j] = 0;
// Add into partial product.
for (j = 0; j < (RS_12_9_POLY_MAXDEG*2); j++)
dst[j] ^= tmp1[j];
}
}
// Computes the combined erasure/error evaluator polynomial (error_locator_poly*syndrome mod z^4)
static void rs_12_9_calc_error_evaluator_poly(rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *syndrome, rs_12_9_poly_t *error_evaluator_poly) {
uint8_t i;
uint8_t product[RS_12_9_POLY_MAXDEG*2];
rs_12_9_multiplicate_polys(product, error_locator_poly, syndrome);
for (i = 0; i < RS_12_9_CHECKSUMSIZE; i++)
error_evaluator_poly->data[i] = product[i];
for (; i < RS_12_9_POLY_MAXDEG; i++)
error_evaluator_poly->data[i] = 0;
}
static uint8_t rs_12_9_compute_discrepancy(rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *syndrome, uint8_t L, uint8_t n) {
uint8_t i;
uint8_t sum = 0;
for (i = 0; i <= L; i++)
sum ^= rs_12_9_galois_multiplication(error_locator_poly->data[i], syndrome->data[n-i]);
return sum;
}
// This finds the coefficients of the error locator polynomial, and then calculates
// the error evaluator polynomial using the Berlekamp-Massey algorithm.
// From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216.
static void rs_12_9_calculate(rs_12_9_poly_t *syndrome, rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *error_evaluator_poly) {
uint8_t n;
uint8_t L = 0;
uint8_t L2;
int8_t k;
uint8_t d;
uint8_t i;
uint8_t psi2[RS_12_9_POLY_MAXDEG];
rs_12_9_poly_t D = { .data = { 0, 1, 0, } };
k = -1;
memset(error_locator_poly, 0, sizeof(rs_12_9_poly_t));
error_locator_poly->data[0] = 1;
for (n = 0; n < RS_12_9_CHECKSUMSIZE; n++) {
d = rs_12_9_compute_discrepancy(error_locator_poly, syndrome, L, n);
if (d != 0) {
// psi2 = error_locator_poly - d*D
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
psi2[i] = error_locator_poly->data[i] ^ rs_12_9_galois_multiplication(d, D.data[i]);
if (L < (n-k)) {
L2 = n-k;
k = n-L;
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
D.data[i] = rs_12_9_galois_multiplication(error_locator_poly->data[i], rs_12_9_galois_inv(d));
L = L2;
}
// error_locator_poly = psi2
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
error_locator_poly->data[i] = psi2[i];
}
rs_12_9_multiply_poly_z(&D);
}
rs_12_9_calc_error_evaluator_poly(error_locator_poly, syndrome, error_evaluator_poly);
}
// The error-locator polynomial's roots are found by looking for the values of a^n where
// evaluating the polynomial yields zero (evaluating rs_12_9_error_locator_poly at
// successive values of alpha (Chien's search)).
static rs_12_9_roots_t *rs_12_9_find_roots(rs_12_9_poly_t *error_locator_poly) {
static rs_12_9_roots_t roots;
uint8_t sum;
uint16_t r;
uint8_t k;
memset(&roots, 0, sizeof(rs_12_9_roots_t));
for (r = 1; r < 256; r++) {
sum = 0;
// Evaluate rs_12_9_error_locator_poly at r
for (k = 0; k < RS_12_9_CHECKSUMSIZE+1; k++)
sum ^= rs_12_9_galois_multiplication(rs_12_9_galois_exp_table_get((k*r) % 255), error_locator_poly->data[k]);
if (sum == 0)
roots.error_locations[roots.errors_num++] = (255-r);
}
return &roots;
}
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome) {
uint8_t i, j;
syndrome->data[0] = syndrome->data[1] = syndrome->data[2] = 0;
for (j = 0; j < 3; j++) {
for (i = 0; i < sizeof(rs_12_9_codeword_t); i++)
syndrome->data[j] = codeword->data[i] ^ rs_12_9_galois_multiplication(rs_12_9_galois_exp_table_get(j+1), syndrome->data[j]);
}
}
// Returns 1 if syndrome differs from all zeroes.
uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome) {
uint8_t i;
for (i = 0; i < 3; i++) {
if (syndrome->data[i] != 0)
return 1;
}
return 0;
}
// Returns 1 if errors have been found and corrected, returns 0 if
// no errors found or errors can't be corrected.
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) {
uint8_t r;
uint8_t i;
uint8_t j;
uint8_t err;
rs_12_9_poly_t error_locator_poly;
rs_12_9_poly_t error_evaluator_poly;
rs_12_9_roots_t *roots;
uint8_t num, denom;
rs_12_9_calculate(syndrome, &error_locator_poly, &error_evaluator_poly);
roots = rs_12_9_find_roots(&error_locator_poly);
*errors_found = roots->errors_num;
if (roots->errors_num == 0)
return RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND;
// Error correction is done using the error-evaluator equation on pp 207.
if (roots->errors_num > 0 && roots->errors_num <= RS_12_9_CHECKSUMSIZE) {
// First check for illegal error locations.
for (r = 0; r < roots->errors_num; r++) {
if (roots->error_locations[r] >= RS_12_9_DATASIZE+RS_12_9_CHECKSUMSIZE)
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CANT_BE_CORRECTED;
}
// Evaluates rs_12_9_error_evaluator_poly/rs_12_9_error_locator_poly' at the roots
// alpha^(-i) for error locs i.
for (r = 0; r < roots->errors_num; r++) {
i = roots->error_locations[r];
// Evaluate rs_12_9_error_evaluator_poly at alpha^(-i)
num = 0;
for (j = 0; j < RS_12_9_POLY_MAXDEG; j++)
num ^= rs_12_9_galois_multiplication(error_evaluator_poly.data[j], rs_12_9_galois_exp_table_get(((255-i)*j) % 255));
// Evaluate rs_12_9_error_evaluator_poly' (derivative) at alpha^(-i). All odd powers disappear.
denom = 0;
for (j = 1; j < RS_12_9_POLY_MAXDEG; j += 2)
denom ^= rs_12_9_galois_multiplication(error_locator_poly.data[j], rs_12_9_galois_exp_table_get(((255-i)*(j-1)) % 255));
err = rs_12_9_galois_multiplication(num, rs_12_9_galois_inv(denom));
//console_log(LOGLEVEL_CODING LOGLEVEL_DEBUG " rs (12,9): error magnitude %#x at byte loc. %u\n", err, sizeof(rs_12_9_codeword_t)-i);
codeword->data[sizeof(rs_12_9_codeword_t)-i-1] ^= err;
}
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED;
}
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CANT_BE_CORRECTED;
}
// Simulates an LFSR with the generator polynomial and calculates checksum bytes for the given data.
rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword) {
// See DMR AI. spec. page 136 for these coefficients.
static uint8_t genpoly[] = { 0x40, 0x38, 0x0e, 0x01 };
static rs_12_9_checksum_t rs_12_9_checksum;
uint8_t i;
uint8_t feedback;
rs_12_9_checksum.bytes[0] = rs_12_9_checksum.bytes[1] = rs_12_9_checksum.bytes[2] = 0;
for (i = 0; i < 9; i++) {
feedback = codeword->data[i] ^ rs_12_9_checksum.bytes[0];
rs_12_9_checksum.bytes[0] = rs_12_9_checksum.bytes[1] ^ rs_12_9_galois_multiplication(genpoly[2], feedback);
rs_12_9_checksum.bytes[1] = rs_12_9_checksum.bytes[2] ^ rs_12_9_galois_multiplication(genpoly[1], feedback);
rs_12_9_checksum.bytes[2] = rs_12_9_galois_multiplication(genpoly[0], feedback);
}
return &rs_12_9_checksum;
}