diff --git a/include/dpmr_const.h b/include/dpmr_const.h
new file mode 100644
index 0000000..cac7039
--- /dev/null
+++ b/include/dpmr_const.h
@@ -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
diff --git a/include/dsd.h b/include/dsd.h
index 9f423b3..e703fb3 100644
--- a/include/dsd.h
+++ b/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);
diff --git a/include/fec.h b/include/fec.h
new file mode 100644
index 0000000..6180f2d
--- /dev/null
+++ b/include/fec.h
@@ -0,0 +1,1448 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB. //
+// //
+// This program 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 as version 3 of the License, or //
+// //
+// This program 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "dsd.h"
+
+unsigned char Hamming_7_4_m_corr[8]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_7_4_m_G[7*4] = {
+ 1, 0, 0, 0, 1, 0, 1,
+ 0, 1, 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_7_4_m_H[7*3] = {
+ 1, 1, 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0, 1, 0,
+ 1, 1, 0, 1, 0, 0, 1
+// 0 1 2 3 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_12_8_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_12_8_m_G[12*8] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_12_8_m_H[12*4] = {
+ 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1
+// 0 1 2 3 4 5 6 7 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_13_9_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_13_9_m_G[13*9] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_13_9_m_H[13*4] = {
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
+// 0 1 2 3 4 5 6 7 8 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_15_11_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_15_11_m_G[15*11] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_15_11_m_H[15*4] = {
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
+// 0 1 2 3 4 5 6 7 8 9 10 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_16_11_4_m_corr[32]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_16_11_4_m_G[16*11] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_16_11_4_m_H[16*5] = {
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_20_8_m_corr[4096][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_20_8_m_G[20*8] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_20_8_m_H[20*12] = {
+ 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_23_12_m_corr[2048][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_23_12_m_G[23*12] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_23_12_m_H[23*11] = {
+ 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_24_12_m_corr[4096][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_24_12_m_G[24*12] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_24_12_m_H[24*12] = {
+ 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char QR_16_7_6_m_corr[512][2]; //!< up to 2 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char QR_16_7_6_m_G[16*7] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char QR_16_7_6_m_H[16*9] = {
+ 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+void Hamming_7_4_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_7_4_m_corr, 0xFF, 8); // initialize with all invalid positions
+ Hamming_7_4_m_corr[0b101] = 0;
+ Hamming_7_4_m_corr[0b111] = 1;
+ Hamming_7_4_m_corr[0b110] = 2;
+ Hamming_7_4_m_corr[0b011] = 3;
+ Hamming_7_4_m_corr[0b100] = 4;
+ Hamming_7_4_m_corr[0b010] = 5;
+ Hamming_7_4_m_corr[0b001] = 6;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 7);
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 7; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_7_4_m_G[7*i + j];
+ }
+ }
+
+ for (i = 0; i < 7; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_7_4_decode(unsigned char *rxBits) // corrects in place
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+
+ for (is = 0; is < 3; is++)
+ {
+ syndromeI += (((rxBits[0] * Hamming_7_4_m_H[7*is + 0])
+ + (rxBits[1] * Hamming_7_4_m_H[7*is + 1])
+ + (rxBits[2] * Hamming_7_4_m_H[7*is + 2])
+ + (rxBits[3] * Hamming_7_4_m_H[7*is + 3])
+ + (rxBits[4] * Hamming_7_4_m_H[7*is + 4])
+ + (rxBits[5] * Hamming_7_4_m_H[7*is + 5])
+ + (rxBits[6] * Hamming_7_4_m_H[7*is + 6])) % 2) << (2-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ if (Hamming_7_4_m_corr[syndromeI] == 0xFF)
+ {
+ return false;
+ }
+ else
+ {
+ rxBits[Hamming_7_4_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_12_8_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_12_8_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_12_8_m_corr[0b1110] = 0;
+ Hamming_12_8_m_corr[0b0111] = 1;
+ Hamming_12_8_m_corr[0b1010] = 2;
+ Hamming_12_8_m_corr[0b0101] = 3;
+ Hamming_12_8_m_corr[0b1011] = 4;
+ Hamming_12_8_m_corr[0b1100] = 5;
+ Hamming_12_8_m_corr[0b0110] = 6;
+ Hamming_12_8_m_corr[0b0011] = 7;
+ Hamming_12_8_m_corr[0b1000] = 8;
+ Hamming_12_8_m_corr[0b0100] = 9;
+ Hamming_12_8_m_corr[0b0010] = 10;
+ Hamming_12_8_m_corr[0b0001] = 11;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_12_8_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 12);
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 12; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_12_8_m_G[12*i + j];
+ }
+ }
+
+ for (i = 0; i < 12; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_12_8_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0;
+ int is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[12*ic + 0] * Hamming_12_8_m_H[12*is + 0])
+ + (rxBits[12*ic + 1] * Hamming_12_8_m_H[12*is + 1])
+ + (rxBits[12*ic + 2] * Hamming_12_8_m_H[12*is + 2])
+ + (rxBits[12*ic + 3] * Hamming_12_8_m_H[12*is + 3])
+ + (rxBits[12*ic + 4] * Hamming_12_8_m_H[12*is + 4])
+ + (rxBits[12*ic + 5] * Hamming_12_8_m_H[12*is + 5])
+ + (rxBits[12*ic + 6] * Hamming_12_8_m_H[12*is + 6])
+ + (rxBits[12*ic + 7] * Hamming_12_8_m_H[12*is + 7])
+ + (rxBits[12*ic + 8] * Hamming_12_8_m_H[12*is + 8])
+ + (rxBits[12*ic + 9] * Hamming_12_8_m_H[12*is + 9])
+ + (rxBits[12*ic + 10] * Hamming_12_8_m_H[12*is + 10])
+ + (rxBits[12*ic + 11] * Hamming_12_8_m_H[12*is + 11])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_12_8_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ }
+ else
+ {
+ rxBits[Hamming_12_8_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ memcpy(&decodedBits[8*ic], &rxBits[12*ic], 8);
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_13_9_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_13_9_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_13_9_m_corr[0b1111] = 0;
+ Hamming_13_9_m_corr[0b1110] = 1;
+ Hamming_13_9_m_corr[0b0111] = 2;
+ Hamming_13_9_m_corr[0b1010] = 3;
+ Hamming_13_9_m_corr[0b0101] = 4;
+ Hamming_13_9_m_corr[0b1011] = 5;
+ Hamming_13_9_m_corr[0b1100] = 6;
+ Hamming_13_9_m_corr[0b0110] = 7;
+ Hamming_13_9_m_corr[0b0011] = 8;
+ Hamming_13_9_m_corr[0b1000] = 9;
+ Hamming_13_9_m_corr[0b0100] = 10;
+ Hamming_13_9_m_corr[0b0010] = 11;
+ Hamming_13_9_m_corr[0b0001] = 12;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_13_9_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 13);
+
+ for (i = 0; i < 9; i++)
+ {
+ for (j = 0; j < 13; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_13_9_m_G[13*i + j];
+ }
+ }
+
+ for (i = 0; i < 13; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_13_9_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[13*ic + 0] * Hamming_13_9_m_H[13*is + 0])
+ + (rxBits[13*ic + 1] * Hamming_13_9_m_H[13*is + 1])
+ + (rxBits[13*ic + 2] * Hamming_13_9_m_H[13*is + 2])
+ + (rxBits[13*ic + 3] * Hamming_13_9_m_H[13*is + 3])
+ + (rxBits[13*ic + 4] * Hamming_13_9_m_H[13*is + 4])
+ + (rxBits[13*ic + 5] * Hamming_13_9_m_H[13*is + 5])
+ + (rxBits[13*ic + 6] * Hamming_13_9_m_H[13*is + 6])
+ + (rxBits[13*ic + 7] * Hamming_13_9_m_H[13*is + 7])
+ + (rxBits[13*ic + 8] * Hamming_13_9_m_H[13*is + 8])
+ + (rxBits[13*ic + 9] * Hamming_13_9_m_H[13*is + 9])
+ + (rxBits[13*ic + 10] * Hamming_13_9_m_H[13*is + 10])
+ + (rxBits[13*ic + 11] * Hamming_13_9_m_H[13*is + 11])
+ + (rxBits[13*ic + 12] * Hamming_13_9_m_H[13*is + 12])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_13_9_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_13_9_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[9*ic], &rxBits[13*ic], 9);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_15_11_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_15_11_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_15_11_m_corr[0b1001] = 0;
+ Hamming_15_11_m_corr[0b1101] = 1;
+ Hamming_15_11_m_corr[0b1111] = 2;
+ Hamming_15_11_m_corr[0b1110] = 3;
+ Hamming_15_11_m_corr[0b0111] = 4;
+ Hamming_15_11_m_corr[0b1010] = 5;
+ Hamming_15_11_m_corr[0b0101] = 6;
+ Hamming_15_11_m_corr[0b1011] = 7;
+ Hamming_15_11_m_corr[0b1100] = 8;
+ Hamming_15_11_m_corr[0b0110] = 9;
+ Hamming_15_11_m_corr[0b0011] = 10;
+ Hamming_15_11_m_corr[0b1000] = 11;
+ Hamming_15_11_m_corr[0b0100] = 12;
+ Hamming_15_11_m_corr[0b0010] = 13;
+ Hamming_15_11_m_corr[0b0001] = 14;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_15_11_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 15);
+
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 15; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_15_11_m_G[15*i + j];
+ }
+ }
+
+ for (i = 0; i < 15; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_15_11_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[15*ic + 0] * Hamming_15_11_m_H[15*is + 0])
+ + (rxBits[15*ic + 1] * Hamming_15_11_m_H[15*is + 1])
+ + (rxBits[15*ic + 2] * Hamming_15_11_m_H[15*is + 2])
+ + (rxBits[15*ic + 3] * Hamming_15_11_m_H[15*is + 3])
+ + (rxBits[15*ic + 4] * Hamming_15_11_m_H[15*is + 4])
+ + (rxBits[15*ic + 5] * Hamming_15_11_m_H[15*is + 5])
+ + (rxBits[15*ic + 6] * Hamming_15_11_m_H[15*is + 6])
+ + (rxBits[15*ic + 7] * Hamming_15_11_m_H[15*is + 7])
+ + (rxBits[15*ic + 8] * Hamming_15_11_m_H[15*is + 8])
+ + (rxBits[15*ic + 9] * Hamming_15_11_m_H[15*is + 9])
+ + (rxBits[15*ic + 10] * Hamming_15_11_m_H[15*is + 10])
+ + (rxBits[15*ic + 11] * Hamming_15_11_m_H[15*is + 11])
+ + (rxBits[15*ic + 12] * Hamming_15_11_m_H[15*is + 12])
+ + (rxBits[15*ic + 13] * Hamming_15_11_m_H[15*is + 13])
+ + (rxBits[15*ic + 14] * Hamming_15_11_m_H[15*is + 14])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_15_11_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_15_11_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[11*ic], &rxBits[15*ic], 11);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_16_11_4_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_16_11_4_m_corr, 0xFF, 32); // initialize with all invalid positions
+ Hamming_16_11_4_m_corr[0b10011] = 0;
+ Hamming_16_11_4_m_corr[0b11010] = 1;
+ Hamming_16_11_4_m_corr[0b11111] = 2;
+ Hamming_16_11_4_m_corr[0b11100] = 3;
+ Hamming_16_11_4_m_corr[0b01110] = 4;
+ Hamming_16_11_4_m_corr[0b10101] = 5;
+ Hamming_16_11_4_m_corr[0b01011] = 6;
+ Hamming_16_11_4_m_corr[0b10110] = 7;
+ Hamming_16_11_4_m_corr[0b11001] = 8;
+ Hamming_16_11_4_m_corr[0b01101] = 9;
+ Hamming_16_11_4_m_corr[0b00111] = 10;
+ Hamming_16_11_4_m_corr[0b10000] = 11;
+ Hamming_16_11_4_m_corr[0b01000] = 12;
+ Hamming_16_11_4_m_corr[0b00100] = 13;
+ Hamming_16_11_4_m_corr[0b00010] = 14;
+ Hamming_16_11_4_m_corr[0b00001] = 15;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_16_11_4_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 16);
+
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_16_11_4_m_G[16*i + j];
+ }
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+ syndromeI = 0; // syndrome index
+ for (is = 0; is < 5; is++)
+ {
+ syndromeI += (((rxBits[16*ic + 0] * Hamming_16_11_4_m_H[16*is + 0])
+ + (rxBits[16*ic + 1] * Hamming_16_11_4_m_H[16*is + 1])
+ + (rxBits[16*ic + 2] * Hamming_16_11_4_m_H[16*is + 2])
+ + (rxBits[16*ic + 3] * Hamming_16_11_4_m_H[16*is + 3])
+ + (rxBits[16*ic + 4] * Hamming_16_11_4_m_H[16*is + 4])
+ + (rxBits[16*ic + 5] * Hamming_16_11_4_m_H[16*is + 5])
+ + (rxBits[16*ic + 6] * Hamming_16_11_4_m_H[16*is + 6])
+ + (rxBits[16*ic + 7] * Hamming_16_11_4_m_H[16*is + 7])
+ + (rxBits[16*ic + 8] * Hamming_16_11_4_m_H[16*is + 8])
+ + (rxBits[16*ic + 9] * Hamming_16_11_4_m_H[16*is + 9])
+ + (rxBits[16*ic + 10] * Hamming_16_11_4_m_H[16*is + 10])
+ + (rxBits[16*ic + 11] * Hamming_16_11_4_m_H[16*is + 11])
+ + (rxBits[16*ic + 12] * Hamming_16_11_4_m_H[16*is + 12])
+ + (rxBits[16*ic + 13] * Hamming_16_11_4_m_H[16*is + 13])
+ + (rxBits[16*ic + 14] * Hamming_16_11_4_m_H[16*is + 14])
+ + (rxBits[16*ic + 15] * Hamming_16_11_4_m_H[16*is + 15])) % 2) << (4-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_16_11_4_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_16_11_4_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[11*ic], &rxBits[16*ic], 11);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Golay_20_8_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset(Golay_20_8_m_corr, 0xFF, 3*4096);
+
+ for (i1 = 0; i1 < 8; i1++)
+ {
+ for (i2 = i1+1; i2 < 8; i2++)
+ {
+ for (i3 = i2+1; i3 < 8; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_20_8_m_H[20*ir + i1] + Golay_20_8_m_H[20*ir + i2] + Golay_20_8_m_H[20*ir + i3]) % 2) << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+ Golay_20_8_m_corr[syndromeI][1] = i2;
+ Golay_20_8_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_20_8_m_H[20*ir + i1] + Golay_20_8_m_H[20*ir + i2]) % 2) << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+ Golay_20_8_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 12; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (11-ip));
+ Golay_20_8_m_corr[syndromeIP][0] = i1;
+ Golay_20_8_m_corr[syndromeIP][1] = i2;
+ Golay_20_8_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += Golay_20_8_m_H[20*ir + i1] << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (11-ip1));
+ Golay_20_8_m_corr[syndromeIP1][0] = i1;
+ Golay_20_8_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_20_8_m_corr[syndromeIP2][0] = i1;
+ Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (11-ip1));
+ Golay_20_8_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_20_8_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
+ Golay_20_8_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_20_8_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_20_8_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 20);
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 20; j++)
+ {
+ encodedBits[j] += origBits[i] * Golay_20_8_m_G[20*i + j];
+ }
+ }
+
+ for (i = 0; i < 20; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_20_8_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 12; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_20_8_m_H[20*is + 0])
+ + (rxBits[1] * Golay_20_8_m_H[20*is + 1])
+ + (rxBits[2] * Golay_20_8_m_H[20*is + 2])
+ + (rxBits[3] * Golay_20_8_m_H[20*is + 3])
+ + (rxBits[4] * Golay_20_8_m_H[20*is + 4])
+ + (rxBits[5] * Golay_20_8_m_H[20*is + 5])
+ + (rxBits[6] * Golay_20_8_m_H[20*is + 6])
+ + (rxBits[7] * Golay_20_8_m_H[20*is + 7])
+ + (rxBits[8] * Golay_20_8_m_H[20*is + 8])
+ + (rxBits[9] * Golay_20_8_m_H[20*is + 9])
+ + (rxBits[10] * Golay_20_8_m_H[20*is + 10])
+ + (rxBits[11] * Golay_20_8_m_H[20*is + 11])
+ + (rxBits[12] * Golay_20_8_m_H[20*is + 12])
+ + (rxBits[13] * Golay_20_8_m_H[20*is + 13])
+ + (rxBits[14] * Golay_20_8_m_H[20*is + 14])
+ + (rxBits[15] * Golay_20_8_m_H[20*is + 15])
+ + (rxBits[16] * Golay_20_8_m_H[20*is + 16])
+ + (rxBits[17] * Golay_20_8_m_H[20*is + 17])
+ + (rxBits[18] * Golay_20_8_m_H[20*is + 18])
+ + (rxBits[19] * Golay_20_8_m_H[20*is + 19])) % 2) << (11-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_20_8_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_20_8_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Golay_23_12_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset(Golay_23_12_m_corr, 0xFF, 3*2048);
+
+ for (i1 = 0; i1 < 12; i1++)
+ {
+ for (i2 = i1+1; i2 < 12; i2++)
+ {
+ for (i3 = i2+1; i3 < 12; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += ((Golay_23_12_m_H[23*ir + i1] + Golay_23_12_m_H[23*ir + i2] + Golay_23_12_m_H[23*ir + i3]) % 2) << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+ Golay_23_12_m_corr[syndromeI][1] = i2;
+ Golay_23_12_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += ((Golay_23_12_m_H[23*ir + i1] + Golay_23_12_m_H[23*ir + i2]) % 2) << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+ Golay_23_12_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 11; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (10-ip));
+ Golay_23_12_m_corr[syndromeIP][0] = i1;
+ Golay_23_12_m_corr[syndromeIP][1] = i2;
+ Golay_23_12_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += Golay_23_12_m_H[23*ir + i1] << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 11; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (10-ip1));
+ Golay_23_12_m_corr[syndromeIP1][0] = i1;
+ Golay_23_12_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
+ Golay_23_12_m_corr[syndromeIP2][0] = i1;
+ Golay_23_12_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 11; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (10-ip1));
+ Golay_23_12_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
+ Golay_23_12_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 11; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (10-ip3));
+ Golay_23_12_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_23_12_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_23_12_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 23);
+
+ for (i = 0; i < 12; i++) // orig bits
+ {
+ for (j = 0; j < 23; j++) // codeword bits
+ {
+ encodedBits[j] += origBits[i] * Golay_23_12_m_G[23*i + j];
+ }
+ }
+
+ for (i = 0; i < 23; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_23_12_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 11; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_23_12_m_H[23*is + 0])
+ + (rxBits[1] * Golay_23_12_m_H[23*is + 1])
+ + (rxBits[2] * Golay_23_12_m_H[23*is + 2])
+ + (rxBits[3] * Golay_23_12_m_H[23*is + 3])
+ + (rxBits[4] * Golay_23_12_m_H[23*is + 4])
+ + (rxBits[5] * Golay_23_12_m_H[23*is + 5])
+ + (rxBits[6] * Golay_23_12_m_H[23*is + 6])
+ + (rxBits[7] * Golay_23_12_m_H[23*is + 7])
+ + (rxBits[8] * Golay_23_12_m_H[23*is + 8])
+ + (rxBits[9] * Golay_23_12_m_H[23*is + 9])
+ + (rxBits[10] * Golay_23_12_m_H[23*is + 10])
+ + (rxBits[11] * Golay_23_12_m_H[23*is + 11])
+ + (rxBits[12] * Golay_23_12_m_H[23*is + 12])
+ + (rxBits[13] * Golay_23_12_m_H[23*is + 13])
+ + (rxBits[14] * Golay_23_12_m_H[23*is + 14])
+ + (rxBits[15] * Golay_23_12_m_H[23*is + 15])
+ + (rxBits[16] * Golay_23_12_m_H[23*is + 16])
+ + (rxBits[17] * Golay_23_12_m_H[23*is + 17])
+ + (rxBits[18] * Golay_23_12_m_H[23*is + 18])
+ + (rxBits[19] * Golay_23_12_m_H[23*is + 19])
+ + (rxBits[20] * Golay_23_12_m_H[23*is + 20])
+ + (rxBits[21] * Golay_23_12_m_H[23*is + 21])
+ + (rxBits[22] * Golay_23_12_m_H[23*is + 22])) % 2) << (10-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_23_12_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_23_12_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Golay_24_12_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset (Golay_24_12_m_corr, 0xFF, 3*4096);
+
+ for (i1 = 0; i1 < 12; i1++)
+ {
+ for (i2 = i1+1; i2 < 12; i2++)
+ {
+ for (i3 = i2+1; i3 < 12; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_24_12_m_H[24*ir + i1] + Golay_24_12_m_H[24*ir + i2] + Golay_24_12_m_H[24*ir + i3]) % 2) << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+ Golay_24_12_m_corr[syndromeI][1] = i2;
+ Golay_24_12_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_24_12_m_H[24*ir + i1] + Golay_24_12_m_H[24*ir + i2]) % 2) << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+ Golay_24_12_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 12; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (11-ip));
+ Golay_24_12_m_corr[syndromeIP][0] = i1;
+ Golay_24_12_m_corr[syndromeIP][1] = i2;
+ Golay_24_12_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += Golay_24_12_m_H[24*ir + i1] << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (11-ip1));
+ Golay_24_12_m_corr[syndromeIP1][0] = i1;
+ Golay_24_12_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_24_12_m_corr[syndromeIP2][0] = i1;
+ Golay_24_12_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (11-ip1));
+ Golay_24_12_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_24_12_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
+ Golay_24_12_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_24_12_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 24);
+
+ for (i = 0; i < 12; i++)
+ {
+ for (j = 0; j < 24; j++)
+ {
+ encodedBits[j] += origBits[i] * Golay_24_12_m_G[24*i + j];
+ }
+ }
+
+ for (i = 0; i < 24; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_24_12_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 12; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_24_12_m_H[24*is + 0])
+ + (rxBits[1] * Golay_24_12_m_H[24*is + 1])
+ + (rxBits[2] * Golay_24_12_m_H[24*is + 2])
+ + (rxBits[3] * Golay_24_12_m_H[24*is + 3])
+ + (rxBits[4] * Golay_24_12_m_H[24*is + 4])
+ + (rxBits[5] * Golay_24_12_m_H[24*is + 5])
+ + (rxBits[6] * Golay_24_12_m_H[24*is + 6])
+ + (rxBits[7] * Golay_24_12_m_H[24*is + 7])
+ + (rxBits[8] * Golay_24_12_m_H[24*is + 8])
+ + (rxBits[9] * Golay_24_12_m_H[24*is + 9])
+ + (rxBits[10] * Golay_24_12_m_H[24*is + 10])
+ + (rxBits[11] * Golay_24_12_m_H[24*is + 11])
+ + (rxBits[12] * Golay_24_12_m_H[24*is + 12])
+ + (rxBits[13] * Golay_24_12_m_H[24*is + 13])
+ + (rxBits[14] * Golay_24_12_m_H[24*is + 14])
+ + (rxBits[15] * Golay_24_12_m_H[24*is + 15])
+ + (rxBits[16] * Golay_24_12_m_H[24*is + 16])
+ + (rxBits[17] * Golay_24_12_m_H[24*is + 17])
+ + (rxBits[18] * Golay_24_12_m_H[24*is + 18])
+ + (rxBits[19] * Golay_24_12_m_H[24*is + 19])
+ + (rxBits[20] * Golay_24_12_m_H[24*is + 20])
+ + (rxBits[21] * Golay_24_12_m_H[24*is + 21])
+ + (rxBits[22] * Golay_24_12_m_H[24*is + 22])
+ + (rxBits[23] * Golay_24_12_m_H[24*is + 23])) % 2) << (11-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_24_12_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_24_12_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void QR_16_7_6_init()
+{
+ int i1 = 0, i2 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0;
+
+ memset(QR_16_7_6_m_corr, 0xFF, 2*512);
+
+ for (i1 = 0; i1 < 7; i1++)
+ {
+ for (i2 = i1+1; i2 < 7; i2++)
+ {
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 9; ir++)
+ {
+ syndromeI += ((QR_16_7_6_m_H[16*ir + i1] + QR_16_7_6_m_H[16*ir + i2]) % 2) << (8-ir);
+ }
+
+ QR_16_7_6_m_corr[syndromeI][0] = i1;
+ QR_16_7_6_m_corr[syndromeI][1] = i2;
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 9; ir++)
+ {
+ syndromeI += QR_16_7_6_m_H[16*ir + i1] << (8-ir);
+ }
+
+ QR_16_7_6_m_corr[syndromeI][0] = i1;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 9; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (8-ip));
+ QR_16_7_6_m_corr[syndromeIP][0] = i1;
+ QR_16_7_6_m_corr[syndromeIP][1] = 7 + ip;
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 9; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (8-ip1));
+ QR_16_7_6_m_corr[syndromeIP1][0] = 7 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 9; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (8-ip2));
+ QR_16_7_6_m_corr[syndromeIP2][0] = 7 + ip1;
+ QR_16_7_6_m_corr[syndromeIP2][1] = 7 + ip2;
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 16);
+
+ for (i = 0; i < 7; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ encodedBits[j] += origBits[i] * QR_16_7_6_m_G[16*i + j];
+ }
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool QR_16_7_6_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 9; is++)
+ {
+ syndromeI += (((rxBits[0] * QR_16_7_6_m_H[16*is + 0])
+ + (rxBits[1] * QR_16_7_6_m_H[16*is + 1])
+ + (rxBits[2] * QR_16_7_6_m_H[16*is + 2])
+ + (rxBits[3] * QR_16_7_6_m_H[16*is + 3])
+ + (rxBits[4] * QR_16_7_6_m_H[16*is + 4])
+ + (rxBits[5] * QR_16_7_6_m_H[16*is + 5])
+ + (rxBits[6] * QR_16_7_6_m_H[16*is + 6])
+ + (rxBits[7] * QR_16_7_6_m_H[16*is + 7])
+ + (rxBits[8] * QR_16_7_6_m_H[16*is + 8])
+ + (rxBits[9] * QR_16_7_6_m_H[16*is + 9])
+ + (rxBits[10] * QR_16_7_6_m_H[16*is + 10])
+ + (rxBits[11] * QR_16_7_6_m_H[16*is + 11])
+ + (rxBits[12] * QR_16_7_6_m_H[16*is + 12])
+ + (rxBits[13] * QR_16_7_6_m_H[16*is + 13])
+ + (rxBits[14] * QR_16_7_6_m_H[16*is + 14])
+ + (rxBits[15] * QR_16_7_6_m_H[16*is + 15])) % 2) << (8-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 2; i++)
+ {
+ if (QR_16_7_6_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[QR_16_7_6_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+/* This function init all FEC functions
+ * it must be called once at startup */
+void InitAllFecFunction(void)
+{
+ Hamming_7_4_init();
+ Hamming_12_8_init();
+ Hamming_13_9_init();
+ Hamming_15_11_init();
+ Hamming_16_11_4_init();
+ Golay_20_8_init();
+ Golay_23_12_init();
+ Golay_24_12_init();
+ QR_16_7_6_init();
+} /* End InitAllFEC() */
+
+
+/* End of file */
diff --git a/src/bptc.c b/src/bptc.c
new file mode 100644
index 0000000..7f6ddff
--- /dev/null
+++ b/src/bptc.c
@@ -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 */
diff --git a/src/dmr_data.c b/src/dmr_data.c
index 8d61c0f..1eddd5f 100644
--- a/src/dmr_data.c
+++ b/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() */
diff --git a/src/dmr_encryption.c b/src/dmr_encryption.c
new file mode 100644
index 0000000..afb8e5a
--- /dev/null
+++ b/src/dmr_encryption.c
@@ -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 */
diff --git a/src/dmr_sync.c b/src/dmr_sync.c
new file mode 100644
index 0000000..857276e
--- /dev/null
+++ b/src/dmr_sync.c
@@ -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 */
diff --git a/src/dmr_voice.c b/src/dmr_voice.c
index b7a76f7..5522a76 100644
--- a/src/dmr_voice.c
+++ b/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() */
diff --git a/src/dpmr_data.c b/src/dpmr_data.c
new file mode 100644
index 0000000..a356ea9
--- /dev/null
+++ b/src/dpmr_data.c
@@ -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 */
diff --git a/src/dpmr_voice.c b/src/dpmr_voice.c
new file mode 100644
index 0000000..c7e4ae8
--- /dev/null
+++ b/src/dpmr_voice.c
@@ -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 */
diff --git a/src/dsd_file.c b/src/dsd_file.c
index a4ec9ca..6eb4dfc 100644
--- a/src/dsd_file.c
+++ b/src/dsd_file.c
@@ -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);
diff --git a/src/dsd_frame.c b/src/dsd_frame.c
index 6044f5b..5b1c47a 100644
--- a/src/dsd_frame.c
+++ b/src/dsd_frame.c
@@ -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
diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c
index e2a7417..44c6fd1 100644
--- a/src/dsd_frame_sync.c
+++ b/src/dsd_frame_sync.c
@@ -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);
diff --git a/src/dsd_main.c b/src/dsd_main.c
index 2d3c38f..7dbe392 100644
--- a/src/dsd_main.c
+++ b/src/dsd_main.c
@@ -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 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);
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
index 92e8e39..173e5a2 100644
--- a/src/dsd_ncurses.c
+++ b/src/dsd_ncurses.c
@@ -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]);
diff --git a/src/fec.c b/src/fec.c
new file mode 100644
index 0000000..6180f2d
--- /dev/null
+++ b/src/fec.c
@@ -0,0 +1,1448 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB. //
+// //
+// This program 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 as version 3 of the License, or //
+// //
+// This program 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "dsd.h"
+
+unsigned char Hamming_7_4_m_corr[8]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_7_4_m_G[7*4] = {
+ 1, 0, 0, 0, 1, 0, 1,
+ 0, 1, 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_7_4_m_H[7*3] = {
+ 1, 1, 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0, 1, 0,
+ 1, 1, 0, 1, 0, 0, 1
+// 0 1 2 3 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_12_8_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_12_8_m_G[12*8] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_12_8_m_H[12*4] = {
+ 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1
+// 0 1 2 3 4 5 6 7 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_13_9_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_13_9_m_G[13*9] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_13_9_m_H[13*4] = {
+ 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
+// 0 1 2 3 4 5 6 7 8 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_15_11_m_corr[16]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_15_11_m_G[15*11] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_15_11_m_H[15*4] = {
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
+// 0 1 2 3 4 5 6 7 8 9 10 <- correctable bit positions
+};
+
+
+// ========================================================================================
+
+
+unsigned char Hamming_16_11_4_m_corr[32]; //!< single bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Hamming_16_11_4_m_G[16*11] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1
+};
+
+//!< Parity check matrix of bits
+const unsigned char Hamming_16_11_4_m_H[16*5] = {
+ 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_20_8_m_corr[4096][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_20_8_m_G[20*8] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_20_8_m_H[20*12] = {
+ 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_23_12_m_corr[2048][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_23_12_m_G[23*12] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_23_12_m_H[23*11] = {
+ 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char Golay_24_12_m_corr[4096][3]; //!< up to 3 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char Golay_24_12_m_G[24*12] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char Golay_24_12_m_H[24*12] = {
+ 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+unsigned char QR_16_7_6_m_corr[512][2]; //!< up to 2 bit error correction by syndrome index
+
+//!< Generator matrix of bits
+const unsigned char QR_16_7_6_m_G[16*7] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1,
+};
+
+//!< Parity check matrix of bits
+const unsigned char QR_16_7_6_m_H[16*9] = {
+ 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+};
+
+
+// ========================================================================================
+
+
+void Hamming_7_4_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_7_4_m_corr, 0xFF, 8); // initialize with all invalid positions
+ Hamming_7_4_m_corr[0b101] = 0;
+ Hamming_7_4_m_corr[0b111] = 1;
+ Hamming_7_4_m_corr[0b110] = 2;
+ Hamming_7_4_m_corr[0b011] = 3;
+ Hamming_7_4_m_corr[0b100] = 4;
+ Hamming_7_4_m_corr[0b010] = 5;
+ Hamming_7_4_m_corr[0b001] = 6;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 7);
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 7; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_7_4_m_G[7*i + j];
+ }
+ }
+
+ for (i = 0; i < 7; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_7_4_decode(unsigned char *rxBits) // corrects in place
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+
+ for (is = 0; is < 3; is++)
+ {
+ syndromeI += (((rxBits[0] * Hamming_7_4_m_H[7*is + 0])
+ + (rxBits[1] * Hamming_7_4_m_H[7*is + 1])
+ + (rxBits[2] * Hamming_7_4_m_H[7*is + 2])
+ + (rxBits[3] * Hamming_7_4_m_H[7*is + 3])
+ + (rxBits[4] * Hamming_7_4_m_H[7*is + 4])
+ + (rxBits[5] * Hamming_7_4_m_H[7*is + 5])
+ + (rxBits[6] * Hamming_7_4_m_H[7*is + 6])) % 2) << (2-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ if (Hamming_7_4_m_corr[syndromeI] == 0xFF)
+ {
+ return false;
+ }
+ else
+ {
+ rxBits[Hamming_7_4_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_12_8_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_12_8_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_12_8_m_corr[0b1110] = 0;
+ Hamming_12_8_m_corr[0b0111] = 1;
+ Hamming_12_8_m_corr[0b1010] = 2;
+ Hamming_12_8_m_corr[0b0101] = 3;
+ Hamming_12_8_m_corr[0b1011] = 4;
+ Hamming_12_8_m_corr[0b1100] = 5;
+ Hamming_12_8_m_corr[0b0110] = 6;
+ Hamming_12_8_m_corr[0b0011] = 7;
+ Hamming_12_8_m_corr[0b1000] = 8;
+ Hamming_12_8_m_corr[0b0100] = 9;
+ Hamming_12_8_m_corr[0b0010] = 10;
+ Hamming_12_8_m_corr[0b0001] = 11;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_12_8_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 12);
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 12; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_12_8_m_G[12*i + j];
+ }
+ }
+
+ for (i = 0; i < 12; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_12_8_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0;
+ int is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[12*ic + 0] * Hamming_12_8_m_H[12*is + 0])
+ + (rxBits[12*ic + 1] * Hamming_12_8_m_H[12*is + 1])
+ + (rxBits[12*ic + 2] * Hamming_12_8_m_H[12*is + 2])
+ + (rxBits[12*ic + 3] * Hamming_12_8_m_H[12*is + 3])
+ + (rxBits[12*ic + 4] * Hamming_12_8_m_H[12*is + 4])
+ + (rxBits[12*ic + 5] * Hamming_12_8_m_H[12*is + 5])
+ + (rxBits[12*ic + 6] * Hamming_12_8_m_H[12*is + 6])
+ + (rxBits[12*ic + 7] * Hamming_12_8_m_H[12*is + 7])
+ + (rxBits[12*ic + 8] * Hamming_12_8_m_H[12*is + 8])
+ + (rxBits[12*ic + 9] * Hamming_12_8_m_H[12*is + 9])
+ + (rxBits[12*ic + 10] * Hamming_12_8_m_H[12*is + 10])
+ + (rxBits[12*ic + 11] * Hamming_12_8_m_H[12*is + 11])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_12_8_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ }
+ else
+ {
+ rxBits[Hamming_12_8_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ memcpy(&decodedBits[8*ic], &rxBits[12*ic], 8);
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_13_9_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_13_9_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_13_9_m_corr[0b1111] = 0;
+ Hamming_13_9_m_corr[0b1110] = 1;
+ Hamming_13_9_m_corr[0b0111] = 2;
+ Hamming_13_9_m_corr[0b1010] = 3;
+ Hamming_13_9_m_corr[0b0101] = 4;
+ Hamming_13_9_m_corr[0b1011] = 5;
+ Hamming_13_9_m_corr[0b1100] = 6;
+ Hamming_13_9_m_corr[0b0110] = 7;
+ Hamming_13_9_m_corr[0b0011] = 8;
+ Hamming_13_9_m_corr[0b1000] = 9;
+ Hamming_13_9_m_corr[0b0100] = 10;
+ Hamming_13_9_m_corr[0b0010] = 11;
+ Hamming_13_9_m_corr[0b0001] = 12;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_13_9_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 13);
+
+ for (i = 0; i < 9; i++)
+ {
+ for (j = 0; j < 13; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_13_9_m_G[13*i + j];
+ }
+ }
+
+ for (i = 0; i < 13; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_13_9_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[13*ic + 0] * Hamming_13_9_m_H[13*is + 0])
+ + (rxBits[13*ic + 1] * Hamming_13_9_m_H[13*is + 1])
+ + (rxBits[13*ic + 2] * Hamming_13_9_m_H[13*is + 2])
+ + (rxBits[13*ic + 3] * Hamming_13_9_m_H[13*is + 3])
+ + (rxBits[13*ic + 4] * Hamming_13_9_m_H[13*is + 4])
+ + (rxBits[13*ic + 5] * Hamming_13_9_m_H[13*is + 5])
+ + (rxBits[13*ic + 6] * Hamming_13_9_m_H[13*is + 6])
+ + (rxBits[13*ic + 7] * Hamming_13_9_m_H[13*is + 7])
+ + (rxBits[13*ic + 8] * Hamming_13_9_m_H[13*is + 8])
+ + (rxBits[13*ic + 9] * Hamming_13_9_m_H[13*is + 9])
+ + (rxBits[13*ic + 10] * Hamming_13_9_m_H[13*is + 10])
+ + (rxBits[13*ic + 11] * Hamming_13_9_m_H[13*is + 11])
+ + (rxBits[13*ic + 12] * Hamming_13_9_m_H[13*is + 12])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_13_9_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_13_9_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[9*ic], &rxBits[13*ic], 9);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_15_11_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_15_11_m_corr, 0xFF, 16); // initialize with all invalid positions
+ Hamming_15_11_m_corr[0b1001] = 0;
+ Hamming_15_11_m_corr[0b1101] = 1;
+ Hamming_15_11_m_corr[0b1111] = 2;
+ Hamming_15_11_m_corr[0b1110] = 3;
+ Hamming_15_11_m_corr[0b0111] = 4;
+ Hamming_15_11_m_corr[0b1010] = 5;
+ Hamming_15_11_m_corr[0b0101] = 6;
+ Hamming_15_11_m_corr[0b1011] = 7;
+ Hamming_15_11_m_corr[0b1100] = 8;
+ Hamming_15_11_m_corr[0b0110] = 9;
+ Hamming_15_11_m_corr[0b0011] = 10;
+ Hamming_15_11_m_corr[0b1000] = 11;
+ Hamming_15_11_m_corr[0b0100] = 12;
+ Hamming_15_11_m_corr[0b0010] = 13;
+ Hamming_15_11_m_corr[0b0001] = 14;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_15_11_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 15);
+
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 15; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_15_11_m_G[15*i + j];
+ }
+ }
+
+ for (i = 0; i < 15; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_15_11_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+
+ syndromeI = 0; // syndrome index
+
+ for (is = 0; is < 4; is++)
+ {
+ syndromeI += (((rxBits[15*ic + 0] * Hamming_15_11_m_H[15*is + 0])
+ + (rxBits[15*ic + 1] * Hamming_15_11_m_H[15*is + 1])
+ + (rxBits[15*ic + 2] * Hamming_15_11_m_H[15*is + 2])
+ + (rxBits[15*ic + 3] * Hamming_15_11_m_H[15*is + 3])
+ + (rxBits[15*ic + 4] * Hamming_15_11_m_H[15*is + 4])
+ + (rxBits[15*ic + 5] * Hamming_15_11_m_H[15*is + 5])
+ + (rxBits[15*ic + 6] * Hamming_15_11_m_H[15*is + 6])
+ + (rxBits[15*ic + 7] * Hamming_15_11_m_H[15*is + 7])
+ + (rxBits[15*ic + 8] * Hamming_15_11_m_H[15*is + 8])
+ + (rxBits[15*ic + 9] * Hamming_15_11_m_H[15*is + 9])
+ + (rxBits[15*ic + 10] * Hamming_15_11_m_H[15*is + 10])
+ + (rxBits[15*ic + 11] * Hamming_15_11_m_H[15*is + 11])
+ + (rxBits[15*ic + 12] * Hamming_15_11_m_H[15*is + 12])
+ + (rxBits[15*ic + 13] * Hamming_15_11_m_H[15*is + 13])
+ + (rxBits[15*ic + 14] * Hamming_15_11_m_H[15*is + 14])) % 2) << (3-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_15_11_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_15_11_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[11*ic], &rxBits[15*ic], 11);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Hamming_16_11_4_init()
+{
+ // correctable bit positions given syndrome bits as index (see above)
+ memset(Hamming_16_11_4_m_corr, 0xFF, 32); // initialize with all invalid positions
+ Hamming_16_11_4_m_corr[0b10011] = 0;
+ Hamming_16_11_4_m_corr[0b11010] = 1;
+ Hamming_16_11_4_m_corr[0b11111] = 2;
+ Hamming_16_11_4_m_corr[0b11100] = 3;
+ Hamming_16_11_4_m_corr[0b01110] = 4;
+ Hamming_16_11_4_m_corr[0b10101] = 5;
+ Hamming_16_11_4_m_corr[0b01011] = 6;
+ Hamming_16_11_4_m_corr[0b10110] = 7;
+ Hamming_16_11_4_m_corr[0b11001] = 8;
+ Hamming_16_11_4_m_corr[0b01101] = 9;
+ Hamming_16_11_4_m_corr[0b00111] = 10;
+ Hamming_16_11_4_m_corr[0b10000] = 11;
+ Hamming_16_11_4_m_corr[0b01000] = 12;
+ Hamming_16_11_4_m_corr[0b00100] = 13;
+ Hamming_16_11_4_m_corr[0b00010] = 14;
+ Hamming_16_11_4_m_corr[0b00001] = 15;
+}
+
+// Not very efficient but encode is used for unit testing only
+void Hamming_16_11_4_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+ memset(encodedBits, 0, 16);
+
+ for (i = 0; i < 11; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ encodedBits[j] += origBits[i] * Hamming_16_11_4_m_G[16*i + j];
+ }
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords)
+{
+ bool correctable = true;
+ int ic = 0, is = 0;
+ int syndromeI = 0; // syndrome index
+
+ for (ic = 0; ic < nbCodewords; ic++)
+ {
+ // calculate syndrome
+ syndromeI = 0; // syndrome index
+ for (is = 0; is < 5; is++)
+ {
+ syndromeI += (((rxBits[16*ic + 0] * Hamming_16_11_4_m_H[16*is + 0])
+ + (rxBits[16*ic + 1] * Hamming_16_11_4_m_H[16*is + 1])
+ + (rxBits[16*ic + 2] * Hamming_16_11_4_m_H[16*is + 2])
+ + (rxBits[16*ic + 3] * Hamming_16_11_4_m_H[16*is + 3])
+ + (rxBits[16*ic + 4] * Hamming_16_11_4_m_H[16*is + 4])
+ + (rxBits[16*ic + 5] * Hamming_16_11_4_m_H[16*is + 5])
+ + (rxBits[16*ic + 6] * Hamming_16_11_4_m_H[16*is + 6])
+ + (rxBits[16*ic + 7] * Hamming_16_11_4_m_H[16*is + 7])
+ + (rxBits[16*ic + 8] * Hamming_16_11_4_m_H[16*is + 8])
+ + (rxBits[16*ic + 9] * Hamming_16_11_4_m_H[16*is + 9])
+ + (rxBits[16*ic + 10] * Hamming_16_11_4_m_H[16*is + 10])
+ + (rxBits[16*ic + 11] * Hamming_16_11_4_m_H[16*is + 11])
+ + (rxBits[16*ic + 12] * Hamming_16_11_4_m_H[16*is + 12])
+ + (rxBits[16*ic + 13] * Hamming_16_11_4_m_H[16*is + 13])
+ + (rxBits[16*ic + 14] * Hamming_16_11_4_m_H[16*is + 14])
+ + (rxBits[16*ic + 15] * Hamming_16_11_4_m_H[16*is + 15])) % 2) << (4-is);
+ }
+
+ // correct bit
+
+ if (syndromeI > 0) // single bit error correction
+ {
+ if (Hamming_16_11_4_m_corr[syndromeI] == 0xFF) // uncorrectable error
+ {
+ correctable = false;
+ break;
+ }
+ else
+ {
+ rxBits[Hamming_16_11_4_m_corr[syndromeI]] ^= 1; // flip bit
+ }
+ }
+
+ // move information bits
+ if (decodedBits)
+ {
+ memcpy(&decodedBits[11*ic], &rxBits[16*ic], 11);
+ }
+ }
+
+ return correctable;
+}
+
+
+// ========================================================================================
+
+
+void Golay_20_8_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset(Golay_20_8_m_corr, 0xFF, 3*4096);
+
+ for (i1 = 0; i1 < 8; i1++)
+ {
+ for (i2 = i1+1; i2 < 8; i2++)
+ {
+ for (i3 = i2+1; i3 < 8; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_20_8_m_H[20*ir + i1] + Golay_20_8_m_H[20*ir + i2] + Golay_20_8_m_H[20*ir + i3]) % 2) << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+ Golay_20_8_m_corr[syndromeI][1] = i2;
+ Golay_20_8_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_20_8_m_H[20*ir + i1] + Golay_20_8_m_H[20*ir + i2]) % 2) << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+ Golay_20_8_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 12; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (11-ip));
+ Golay_20_8_m_corr[syndromeIP][0] = i1;
+ Golay_20_8_m_corr[syndromeIP][1] = i2;
+ Golay_20_8_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += Golay_20_8_m_H[20*ir + i1] << (11-ir);
+ }
+
+ Golay_20_8_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (11-ip1));
+ Golay_20_8_m_corr[syndromeIP1][0] = i1;
+ Golay_20_8_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_20_8_m_corr[syndromeIP2][0] = i1;
+ Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (11-ip1));
+ Golay_20_8_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_20_8_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
+ Golay_20_8_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_20_8_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_20_8_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_20_8_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 20);
+
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 20; j++)
+ {
+ encodedBits[j] += origBits[i] * Golay_20_8_m_G[20*i + j];
+ }
+ }
+
+ for (i = 0; i < 20; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_20_8_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 12; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_20_8_m_H[20*is + 0])
+ + (rxBits[1] * Golay_20_8_m_H[20*is + 1])
+ + (rxBits[2] * Golay_20_8_m_H[20*is + 2])
+ + (rxBits[3] * Golay_20_8_m_H[20*is + 3])
+ + (rxBits[4] * Golay_20_8_m_H[20*is + 4])
+ + (rxBits[5] * Golay_20_8_m_H[20*is + 5])
+ + (rxBits[6] * Golay_20_8_m_H[20*is + 6])
+ + (rxBits[7] * Golay_20_8_m_H[20*is + 7])
+ + (rxBits[8] * Golay_20_8_m_H[20*is + 8])
+ + (rxBits[9] * Golay_20_8_m_H[20*is + 9])
+ + (rxBits[10] * Golay_20_8_m_H[20*is + 10])
+ + (rxBits[11] * Golay_20_8_m_H[20*is + 11])
+ + (rxBits[12] * Golay_20_8_m_H[20*is + 12])
+ + (rxBits[13] * Golay_20_8_m_H[20*is + 13])
+ + (rxBits[14] * Golay_20_8_m_H[20*is + 14])
+ + (rxBits[15] * Golay_20_8_m_H[20*is + 15])
+ + (rxBits[16] * Golay_20_8_m_H[20*is + 16])
+ + (rxBits[17] * Golay_20_8_m_H[20*is + 17])
+ + (rxBits[18] * Golay_20_8_m_H[20*is + 18])
+ + (rxBits[19] * Golay_20_8_m_H[20*is + 19])) % 2) << (11-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_20_8_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_20_8_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Golay_23_12_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset(Golay_23_12_m_corr, 0xFF, 3*2048);
+
+ for (i1 = 0; i1 < 12; i1++)
+ {
+ for (i2 = i1+1; i2 < 12; i2++)
+ {
+ for (i3 = i2+1; i3 < 12; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += ((Golay_23_12_m_H[23*ir + i1] + Golay_23_12_m_H[23*ir + i2] + Golay_23_12_m_H[23*ir + i3]) % 2) << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+ Golay_23_12_m_corr[syndromeI][1] = i2;
+ Golay_23_12_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += ((Golay_23_12_m_H[23*ir + i1] + Golay_23_12_m_H[23*ir + i2]) % 2) << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+ Golay_23_12_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 11; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (10-ip));
+ Golay_23_12_m_corr[syndromeIP][0] = i1;
+ Golay_23_12_m_corr[syndromeIP][1] = i2;
+ Golay_23_12_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 11; ir++)
+ {
+ syndromeI += Golay_23_12_m_H[23*ir + i1] << (10-ir);
+ }
+
+ Golay_23_12_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 11; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (10-ip1));
+ Golay_23_12_m_corr[syndromeIP1][0] = i1;
+ Golay_23_12_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
+ Golay_23_12_m_corr[syndromeIP2][0] = i1;
+ Golay_23_12_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 11; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (10-ip1));
+ Golay_23_12_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 11; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (10-ip2));
+ Golay_23_12_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 11; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (10-ip3));
+ Golay_23_12_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_23_12_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_23_12_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_23_12_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 23);
+
+ for (i = 0; i < 12; i++) // orig bits
+ {
+ for (j = 0; j < 23; j++) // codeword bits
+ {
+ encodedBits[j] += origBits[i] * Golay_23_12_m_G[23*i + j];
+ }
+ }
+
+ for (i = 0; i < 23; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_23_12_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 11; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_23_12_m_H[23*is + 0])
+ + (rxBits[1] * Golay_23_12_m_H[23*is + 1])
+ + (rxBits[2] * Golay_23_12_m_H[23*is + 2])
+ + (rxBits[3] * Golay_23_12_m_H[23*is + 3])
+ + (rxBits[4] * Golay_23_12_m_H[23*is + 4])
+ + (rxBits[5] * Golay_23_12_m_H[23*is + 5])
+ + (rxBits[6] * Golay_23_12_m_H[23*is + 6])
+ + (rxBits[7] * Golay_23_12_m_H[23*is + 7])
+ + (rxBits[8] * Golay_23_12_m_H[23*is + 8])
+ + (rxBits[9] * Golay_23_12_m_H[23*is + 9])
+ + (rxBits[10] * Golay_23_12_m_H[23*is + 10])
+ + (rxBits[11] * Golay_23_12_m_H[23*is + 11])
+ + (rxBits[12] * Golay_23_12_m_H[23*is + 12])
+ + (rxBits[13] * Golay_23_12_m_H[23*is + 13])
+ + (rxBits[14] * Golay_23_12_m_H[23*is + 14])
+ + (rxBits[15] * Golay_23_12_m_H[23*is + 15])
+ + (rxBits[16] * Golay_23_12_m_H[23*is + 16])
+ + (rxBits[17] * Golay_23_12_m_H[23*is + 17])
+ + (rxBits[18] * Golay_23_12_m_H[23*is + 18])
+ + (rxBits[19] * Golay_23_12_m_H[23*is + 19])
+ + (rxBits[20] * Golay_23_12_m_H[23*is + 20])
+ + (rxBits[21] * Golay_23_12_m_H[23*is + 21])
+ + (rxBits[22] * Golay_23_12_m_H[23*is + 22])) % 2) << (10-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_23_12_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_23_12_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void Golay_24_12_init()
+{
+ int i1 = 0, i2 = 0, i3 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0, ip3 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0, syndromeIP3 = 0;
+
+ memset (Golay_24_12_m_corr, 0xFF, 3*4096);
+
+ for (i1 = 0; i1 < 12; i1++)
+ {
+ for (i2 = i1+1; i2 < 12; i2++)
+ {
+ for (i3 = i2+1; i3 < 12; i3++)
+ {
+ // 3 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_24_12_m_H[24*ir + i1] + Golay_24_12_m_H[24*ir + i2] + Golay_24_12_m_H[24*ir + i3]) % 2) << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+ Golay_24_12_m_corr[syndromeI][1] = i2;
+ Golay_24_12_m_corr[syndromeI][2] = i3;
+ }
+
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += ((Golay_24_12_m_H[24*ir + i1] + Golay_24_12_m_H[24*ir + i2]) % 2) << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+ Golay_24_12_m_corr[syndromeI][1] = i2;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 12; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (11-ip));
+ Golay_24_12_m_corr[syndromeIP][0] = i1;
+ Golay_24_12_m_corr[syndromeIP][1] = i2;
+ Golay_24_12_m_corr[syndromeIP][2] = 12 + ip;
+ }
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 12; ir++)
+ {
+ syndromeI += Golay_24_12_m_H[24*ir + i1] << (11-ir);
+ }
+
+ Golay_24_12_m_corr[syndromeI][0] = i1;
+
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 more bit flip in parity
+ {
+ syndromeIP1 = syndromeI ^ (1 << (11-ip1));
+ Golay_24_12_m_corr[syndromeIP1][0] = i1;
+ Golay_24_12_m_corr[syndromeIP1][1] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_24_12_m_corr[syndromeIP2][0] = i1;
+ Golay_24_12_m_corr[syndromeIP2][1] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP2][2] = 12 + ip2;
+ }
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 12; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (11-ip1));
+ Golay_24_12_m_corr[syndromeIP1][0] = 12 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 12; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (11-ip2));
+ Golay_24_12_m_corr[syndromeIP2][0] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP2][1] = 12 + ip2;
+
+ for (ip3 = ip2+1; ip3 < 12; ip3++) // 1 more bit flip in parity
+ {
+ syndromeIP3 = syndromeIP2 ^ (1 << (11-ip3));
+ Golay_24_12_m_corr[syndromeIP3][0] = 12 + ip1;
+ Golay_24_12_m_corr[syndromeIP3][1] = 12 + ip2;
+ Golay_24_12_m_corr[syndromeIP3][2] = 12 + ip3;
+ }
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 24);
+
+ for (i = 0; i < 12; i++)
+ {
+ for (j = 0; j < 24; j++)
+ {
+ encodedBits[j] += origBits[i] * Golay_24_12_m_G[24*i + j];
+ }
+ }
+
+ for (i = 0; i < 24; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool Golay_24_12_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 12; is++)
+ {
+ syndromeI += (((rxBits[0] * Golay_24_12_m_H[24*is + 0])
+ + (rxBits[1] * Golay_24_12_m_H[24*is + 1])
+ + (rxBits[2] * Golay_24_12_m_H[24*is + 2])
+ + (rxBits[3] * Golay_24_12_m_H[24*is + 3])
+ + (rxBits[4] * Golay_24_12_m_H[24*is + 4])
+ + (rxBits[5] * Golay_24_12_m_H[24*is + 5])
+ + (rxBits[6] * Golay_24_12_m_H[24*is + 6])
+ + (rxBits[7] * Golay_24_12_m_H[24*is + 7])
+ + (rxBits[8] * Golay_24_12_m_H[24*is + 8])
+ + (rxBits[9] * Golay_24_12_m_H[24*is + 9])
+ + (rxBits[10] * Golay_24_12_m_H[24*is + 10])
+ + (rxBits[11] * Golay_24_12_m_H[24*is + 11])
+ + (rxBits[12] * Golay_24_12_m_H[24*is + 12])
+ + (rxBits[13] * Golay_24_12_m_H[24*is + 13])
+ + (rxBits[14] * Golay_24_12_m_H[24*is + 14])
+ + (rxBits[15] * Golay_24_12_m_H[24*is + 15])
+ + (rxBits[16] * Golay_24_12_m_H[24*is + 16])
+ + (rxBits[17] * Golay_24_12_m_H[24*is + 17])
+ + (rxBits[18] * Golay_24_12_m_H[24*is + 18])
+ + (rxBits[19] * Golay_24_12_m_H[24*is + 19])
+ + (rxBits[20] * Golay_24_12_m_H[24*is + 20])
+ + (rxBits[21] * Golay_24_12_m_H[24*is + 21])
+ + (rxBits[22] * Golay_24_12_m_H[24*is + 22])
+ + (rxBits[23] * Golay_24_12_m_H[24*is + 23])) % 2) << (11-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 3; i++)
+ {
+ if (Golay_24_12_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[Golay_24_12_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+void QR_16_7_6_init()
+{
+ int i1 = 0, i2 = 0, ir = 0, ip = 0;
+ int syndromeI = 0, syndromeIP = 0;
+ int ip1 = 0, ip2 = 0;
+ int syndromeIP1 = 0, syndromeIP2 = 0;
+
+ memset(QR_16_7_6_m_corr, 0xFF, 2*512);
+
+ for (i1 = 0; i1 < 7; i1++)
+ {
+ for (i2 = i1+1; i2 < 7; i2++)
+ {
+ // 2 bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 9; ir++)
+ {
+ syndromeI += ((QR_16_7_6_m_H[16*ir + i1] + QR_16_7_6_m_H[16*ir + i2]) % 2) << (8-ir);
+ }
+
+ QR_16_7_6_m_corr[syndromeI][0] = i1;
+ QR_16_7_6_m_corr[syndromeI][1] = i2;
+ }
+
+ // single bit patterns
+ syndromeI = 0;
+
+ for (ir = 0; ir < 9; ir++)
+ {
+ syndromeI += QR_16_7_6_m_H[16*ir + i1] << (8-ir);
+ }
+
+ QR_16_7_6_m_corr[syndromeI][0] = i1;
+
+ // 1 possible bit flip left in the parity part
+ for (ip = 0; ip < 9; ip++)
+ {
+ syndromeIP = syndromeI ^ (1 << (8-ip));
+ QR_16_7_6_m_corr[syndromeIP][0] = i1;
+ QR_16_7_6_m_corr[syndromeIP][1] = 7 + ip;
+ }
+ }
+
+ // no bit patterns (in message) -> all in parity
+ for (ip1 = 0; ip1 < 9; ip1++) // 1 bit flip in parity
+ {
+ syndromeIP1 = (1 << (8-ip1));
+ QR_16_7_6_m_corr[syndromeIP1][0] = 7 + ip1;
+
+ for (ip2 = ip1+1; ip2 < 9; ip2++) // 1 more bit flip in parity
+ {
+ syndromeIP2 = syndromeIP1 ^ (1 << (8-ip2));
+ QR_16_7_6_m_corr[syndromeIP2][0] = 7 + ip1;
+ QR_16_7_6_m_corr[syndromeIP2][1] = 7 + ip2;
+ }
+ }
+}
+
+// Not very efficient but encode is used for unit testing only
+void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits)
+{
+ int i = 0, j = 0;
+
+ memset(encodedBits, 0, 16);
+
+ for (i = 0; i < 7; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ encodedBits[j] += origBits[i] * QR_16_7_6_m_G[16*i + j];
+ }
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ encodedBits[i] %= 2;
+ }
+}
+
+bool QR_16_7_6_decode(unsigned char *rxBits)
+{
+ unsigned int syndromeI = 0; // syndrome index
+ int is = 0;
+ int i = 0;
+
+ for (is = 0; is < 9; is++)
+ {
+ syndromeI += (((rxBits[0] * QR_16_7_6_m_H[16*is + 0])
+ + (rxBits[1] * QR_16_7_6_m_H[16*is + 1])
+ + (rxBits[2] * QR_16_7_6_m_H[16*is + 2])
+ + (rxBits[3] * QR_16_7_6_m_H[16*is + 3])
+ + (rxBits[4] * QR_16_7_6_m_H[16*is + 4])
+ + (rxBits[5] * QR_16_7_6_m_H[16*is + 5])
+ + (rxBits[6] * QR_16_7_6_m_H[16*is + 6])
+ + (rxBits[7] * QR_16_7_6_m_H[16*is + 7])
+ + (rxBits[8] * QR_16_7_6_m_H[16*is + 8])
+ + (rxBits[9] * QR_16_7_6_m_H[16*is + 9])
+ + (rxBits[10] * QR_16_7_6_m_H[16*is + 10])
+ + (rxBits[11] * QR_16_7_6_m_H[16*is + 11])
+ + (rxBits[12] * QR_16_7_6_m_H[16*is + 12])
+ + (rxBits[13] * QR_16_7_6_m_H[16*is + 13])
+ + (rxBits[14] * QR_16_7_6_m_H[16*is + 14])
+ + (rxBits[15] * QR_16_7_6_m_H[16*is + 15])) % 2) << (8-is);
+ }
+
+ if (syndromeI > 0)
+ {
+ i = 0;
+
+ for (; i < 2; i++)
+ {
+ if (QR_16_7_6_m_corr[syndromeI][i] == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ rxBits[QR_16_7_6_m_corr[syndromeI][i]] ^= 1; // flip bit
+ }
+ }
+
+ if (i == 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+// ========================================================================================
+
+
+/* This function init all FEC functions
+ * it must be called once at startup */
+void InitAllFecFunction(void)
+{
+ Hamming_7_4_init();
+ Hamming_12_8_init();
+ Hamming_13_9_init();
+ Hamming_15_11_init();
+ Hamming_16_11_4_init();
+ Golay_20_8_init();
+ Golay_23_12_init();
+ Golay_24_12_init();
+ QR_16_7_6_init();
+} /* End InitAllFEC() */
+
+
+/* End of file */
diff --git a/src/rs-12-9.c b/src/rs-12-9.c
new file mode 100644
index 0000000..f64ac2d
--- /dev/null
+++ b/src/rs-12-9.c
@@ -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 .
+**/
+
+// 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
+
+#include
+#include
+
+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;
+}