mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 09:17:20 -05:00
Staging for DMR Improvements
Staging for DMR Improvements
This commit is contained in:
76
include/dpmr_const.h
Normal file
76
include/dpmr_const.h
Normal 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
|
||||
262
include/dsd.h
262
include/dsd.h
@@ -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
1448
include/fec.h
Normal file
File diff suppressed because it is too large
Load Diff
560
src/bptc.c
Normal file
560
src/bptc.c
Normal 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 */
|
||||
513
src/dmr_data.c
513
src/dmr_data.c
@@ -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
115
src/dmr_encryption.c
Normal 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
839
src/dmr_sync.c
Normal 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 */
|
||||
880
src/dmr_voice.c
880
src/dmr_voice.c
@@ -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
278
src/dpmr_data.c
Normal 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
919
src/dpmr_voice.c
Normal 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 */
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
316
src/rs-12-9.c
Normal file
316
src/rs-12-9.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user