mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
Merge pull request #47 from lwvmobile/pulsedmr
Staging for DMR Improvements
This commit is contained in:
30
README.md
30
README.md
@@ -4,14 +4,14 @@ This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/
|
||||

|
||||
|
||||
## Example Usage - NCurses Terminal and Log Console to log file
|
||||
`./dsd -fa -N 2> voice.log`
|
||||
`./dsd -N 2> voice.log`
|
||||
|
||||
in second terminal, same folder, run:
|
||||
|
||||
`tail -n 40 -f voice.log`
|
||||
|
||||
## Example Usage - RTL
|
||||
`dsd -fi -i rtl -o pulse -c 154.9875M -P -2 -D 1 -G 36 -L 70 -U 6021 -Y 12`
|
||||
`dsd -fi -i rtl -c 154.9875M -P -2 -D 1 -G 36 -L 70 -U 6021 -Y 12`
|
||||
|
||||
```
|
||||
-i rtl to use rtl_fm (default is -i pulse for pulse audio)
|
||||
@@ -34,7 +34,6 @@ in second terminal, same folder, run:
|
||||
|
||||
-Y 12 set rtl VFO bandwidth in kHz, (default = 48)(6, 8, 12, 16, 24, 48)
|
||||
|
||||
-W Monitor Source Audio (WIP!) (Currently disabled on PulseAudio branch)
|
||||
```
|
||||
|
||||
### Note
|
||||
@@ -47,29 +46,34 @@ in second terminal, same folder, run:
|
||||
```
|
||||
Yes, it really is this simple now
|
||||
|
||||
-fa Auto-detect frame type
|
||||
-fa Auto-detect frame type, is default
|
||||
|
||||
sans NXDN or Provoice, need to specify -fp, -fi, or -fn
|
||||
pulse audio are set as default input and output methods
|
||||
sans NXDN, dPMR, or Provoice, need to specify -fp, -fd, -fi, or -fn respectively
|
||||
pulse audio is set as default input and output methods
|
||||
|
||||
```
|
||||
## Example STDIN UDP from GQRX or SDR++, output to Pulse Audio, and save wav files
|
||||
`socat stdio udp-listen:7355 | dsd -fi -i - -o pulse -w nxdn.wav`
|
||||
|
||||
## Example Usage - Extra Information for Academic Study and Logging
|
||||
`dsd -d ./MBE/ -Z -pu 2>> voice.log`
|
||||
|
||||
in second terminal, same folder, run:
|
||||
|
||||
`tail -n 40 -f voice.log`
|
||||
|
||||
## Roadmap
|
||||
The Current list of objectives include:
|
||||
|
||||
1. ~~Random Tinkering~~ More Random Tinkering
|
||||
|
||||
2. Implemented Pulse Audio and ~~Remove PortAudio and~~ Remove OSS, including SOLARIS/APPLE/BSD methods, and Retain PortAudio as Optional (need to re-enable in CMakeLists.txt file)
|
||||
2. ~~Implemented Pulse Audio~~ Remove PortAudio, improve Pulse Audio for stereo output and channel/slot separation.
|
||||
|
||||
3. Improve NXDN and DMR support
|
||||
3. ~~Improve NXDN and DMR support~~ Continue to improve ~~NXDN and DMR~~ all data and voice decoding.
|
||||
|
||||
4. More Concise Printouts - Ncurses
|
||||
4. ~~More Concise Printouts - Ncurses~~
|
||||
|
||||
5. ~~Improve Monitor Source Audio (if #2 on list is up and working)~~ Not currently playing well with Pulse Audio, need to re-evaluate
|
||||
|
||||
6. ~~Make simple to use installer script.~~ Working on script now, also have full build and install guide down below
|
||||
5. ~~Make simple to use installer script.~~
|
||||
|
||||
## How to clone, check out, and build this branch
|
||||
|
||||
@@ -84,7 +88,7 @@ chmod +x install.sh
|
||||
```
|
||||
|
||||
### Ubuntu 18.04/LM19/Buster Note:
|
||||
Or you can elect to manually follow the steps down below. Do NOT Manually build and install ITPP 4.3.1 on older systems, it is currently not wanting to build on Ubuntu 18.04 and Linux Mint 19. Install it from the repository instead.
|
||||
The above install.sh should now function on older system types. You can elect to manually follow the steps down below. Do NOT Manually build and install ITPP 4.3.1 on older systems, it is currently not wanting to build on Ubuntu 18.04 and Linux Mint 19. Install it from the repository instead.
|
||||
|
||||
## Manual Install
|
||||
|
||||
|
||||
BIN
dsd-fme.png
BIN
dsd-fme.png
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 79 KiB |
76
include/dpmr_const.h
Normal file
76
include/dpmr_const.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int dPmrW[36];
|
||||
extern const int dPmrX[36];
|
||||
extern const int dPmrY[36];
|
||||
extern const int dPmrZ[36];
|
||||
|
||||
//#else
|
||||
/*
|
||||
* dPMR AMBE interleave schedule
|
||||
*/
|
||||
// bit 1
|
||||
const int dPmrW[36] = {
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int dPmrX[36] = {
|
||||
23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
11, 9, 10, 8, 9, 7,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
// bit 0
|
||||
const int dPmrY[36] = {
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int dPmrZ[36] = {
|
||||
5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
16, 5, 15, 4, 14, 3,
|
||||
13, 2, 12, 1, 11, 0
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
||||
284
include/dsd.h
284
include/dsd.h
@@ -42,8 +42,9 @@
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
#include <pulse/simple.h> //PULSE AUDIO
|
||||
#include <pulse/error.h> //PULSE AUDIO
|
||||
//#include <pulse/pulseaudio.h> //PUlSE AUDIO
|
||||
|
||||
#define SAMPLE_RATE_IN 48000 //48000
|
||||
#define SAMPLE_RATE_OUT 8000 //8000,
|
||||
@@ -147,9 +148,117 @@ 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) */
|
||||
unsigned int LeftOvers; //what is the 8 bits for that isn't used
|
||||
}FullLinkControlPDU_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TimeSlotRawVoiceFrame_t TimeSlotRawVoiceFrame[6]; /* A voice superframe contains 6 timeslot voice frame */
|
||||
TimeSlotDeinterleavedVoiceFrame_t TimeSlotDeinterleavedVoiceFrame[6];
|
||||
TimeSlotAmbeVoiceFrame_t TimeSlotAmbeVoiceFrame[6];
|
||||
FullLinkControlPDU_t FullLC;
|
||||
} TimeSlotVoiceSuperFrame_t;
|
||||
|
||||
//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;
|
||||
@@ -240,6 +349,15 @@ typedef struct
|
||||
int use_ncurses_terminal;
|
||||
int reset_state;
|
||||
int payload;
|
||||
char output_name[1024];
|
||||
//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;
|
||||
|
||||
@@ -250,12 +368,20 @@ typedef struct
|
||||
int repeat;
|
||||
short *audio_out_buf;
|
||||
short *audio_out_buf_p;
|
||||
short *audio_out_bufR;
|
||||
short *audio_out_buf_pR;
|
||||
float *audio_out_float_buf;
|
||||
float *audio_out_float_buf_p;
|
||||
float *audio_out_float_bufR;
|
||||
float *audio_out_float_buf_pR;
|
||||
float audio_out_temp_buf[160];
|
||||
float *audio_out_temp_buf_p;
|
||||
float audio_out_temp_bufR[160];
|
||||
float *audio_out_temp_buf_pR;
|
||||
int audio_out_idx;
|
||||
int audio_out_idx2;
|
||||
int audio_out_idxR;
|
||||
int audio_out_idx2R;
|
||||
//int wav_out_bytes;
|
||||
int center;
|
||||
int jitter;
|
||||
@@ -274,6 +400,8 @@ typedef struct
|
||||
int midx;
|
||||
char err_str[64]; //actual error errorbars
|
||||
char err_buf[64]; //make copy of err_str for comparison, only have string print when strcmp is different??
|
||||
char err_strR[64];
|
||||
char err_bufR[64];
|
||||
char fsubtype[16];
|
||||
char ftype[16];
|
||||
int symbolcnt;
|
||||
@@ -295,7 +423,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;
|
||||
@@ -312,6 +440,8 @@ typedef struct
|
||||
int payload_algid;
|
||||
int payload_keyid;
|
||||
int payload_mfid;
|
||||
int payload_mi;
|
||||
unsigned long long int K;
|
||||
|
||||
unsigned int debug_audio_errors;
|
||||
unsigned int debug_header_errors;
|
||||
@@ -344,6 +474,10 @@ typedef struct
|
||||
unsigned int dmr_color_code;
|
||||
unsigned int nxdn_last_ran;
|
||||
unsigned int nxdn_last_rid;
|
||||
unsigned int nxdn_last_tg;
|
||||
unsigned int nxdn_cipher_type;
|
||||
unsigned int nxdn_key;
|
||||
char nxdn_call_type[1024];
|
||||
//borrow from LEH
|
||||
NxdnSacchRawPart_t NxdnSacchRawPart[4];
|
||||
NxdnFacch1RawPart_t NxdnFacch1RawPart[2];
|
||||
@@ -356,9 +490,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 +593,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 +739,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 ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20]);
|
||||
|
||||
void Hamming_7_4_init();
|
||||
void Hamming_7_4_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Hamming_7_4_decode(unsigned char *rxBits);
|
||||
|
||||
void Hamming_12_8_init();
|
||||
void Hamming_12_8_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Hamming_12_8_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
|
||||
|
||||
void Hamming_13_9_init();
|
||||
void Hamming_13_9_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Hamming_13_9_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
|
||||
|
||||
void Hamming_15_11_init();
|
||||
void Hamming_15_11_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Hamming_15_11_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
|
||||
|
||||
void Hamming_16_11_4_init();
|
||||
void Hamming_16_11_4_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Hamming_16_11_4_decode(unsigned char *rxBits, unsigned char *decodedBits, int nbCodewords);
|
||||
|
||||
void Golay_20_8_init();
|
||||
void Golay_20_8_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Golay_20_8_decode(unsigned char *rxBits);
|
||||
|
||||
void Golay_23_12_init();
|
||||
void Golay_23_12_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Golay_23_12_decode(unsigned char *rxBits);
|
||||
|
||||
void Golay_24_12_init();
|
||||
void Golay_24_12_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool Golay_24_12_decode(unsigned char *rxBits);
|
||||
|
||||
void QR_16_7_6_init();
|
||||
void QR_16_7_6_encode(unsigned char *origBits, unsigned char *encodedBits);
|
||||
bool QR_16_7_6_decode(unsigned char *rxBits);
|
||||
|
||||
void InitAllFecFunction(void);
|
||||
|
||||
//end borrow from LEH
|
||||
|
||||
void resetState (dsd_state * state);
|
||||
|
||||
1448
include/fec.h
Normal file
1448
include/fec.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -65,7 +65,7 @@ extern const int DSDNXDN_UDCH_m_PunctureList[58];
|
||||
//NXDN_DCALL_REC_RESP = 0b001010, /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */
|
||||
#define NXDN_DCALL_ASSGN = 0b001110
|
||||
#define NXDN_DCALL_ASSGN_DUP = 0b001101
|
||||
#define NXDN_IDLE = 0b010000
|
||||
#define NXDN_IDLE 0b010000
|
||||
#define NXDN_DISC_REQ = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
|
||||
#define NXDN_DISC = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */
|
||||
|
||||
|
||||
560
src/bptc.c
Normal file
560
src/bptc.c
Normal file
@@ -0,0 +1,560 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : bptc.c
|
||||
Author : MotoTRBO_Encrypted_DSD_Author
|
||||
Version : 1.0
|
||||
Date : 2017 - December - 11
|
||||
Copyright : None
|
||||
Description : BPTC library source
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/* Include ------------------------------------------------------------------*/
|
||||
#include "dsd.h"
|
||||
|
||||
|
||||
/* Define -------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Global variables ---------------------------------------------------------*/
|
||||
const uint8_t BPTCInterleavingIndex[196] =
|
||||
{
|
||||
0, 181, 166, 151,
|
||||
136, 121, 106, 91,
|
||||
76, 61, 46, 31,
|
||||
16, 1, 182, 167,
|
||||
152, 137, 122, 107,
|
||||
92, 77, 62, 47,
|
||||
32, 17, 2, 183,
|
||||
168, 153, 138, 123,
|
||||
108, 93, 78, 63,
|
||||
48, 33, 18, 3,
|
||||
184, 169, 154, 139,
|
||||
124, 109, 94, 79,
|
||||
64, 49, 34, 19,
|
||||
4, 185, 170, 155,
|
||||
140, 125, 110, 95,
|
||||
80, 65, 50, 35,
|
||||
20, 5, 186, 171,
|
||||
156, 141, 126, 111,
|
||||
96, 81, 66, 51,
|
||||
36, 21, 6, 187,
|
||||
172, 157, 142, 127,
|
||||
112, 97, 82, 67,
|
||||
52, 37, 22, 7,
|
||||
188, 173, 158, 143,
|
||||
128, 113, 98, 83,
|
||||
68, 53, 38, 23,
|
||||
8, 189, 174, 159,
|
||||
144, 129, 114, 99,
|
||||
84, 69, 54, 39,
|
||||
24, 9, 190, 175,
|
||||
160, 145, 130, 115,
|
||||
100, 85, 70, 55,
|
||||
40, 25, 10, 191,
|
||||
176, 161, 146, 131,
|
||||
116, 101, 86, 71,
|
||||
56, 41, 26, 11,
|
||||
192, 177, 162, 147,
|
||||
132, 117, 102, 87,
|
||||
72, 57, 42, 27,
|
||||
12, 193, 178, 163,
|
||||
148, 133, 118, 103,
|
||||
88, 73, 58, 43,
|
||||
28, 13, 194, 179,
|
||||
164, 149, 134, 119,
|
||||
104, 89, 74, 59,
|
||||
44, 29, 14, 195,
|
||||
180, 165, 150, 135,
|
||||
120, 105, 90, 75,
|
||||
60, 45, 30, 15
|
||||
};
|
||||
|
||||
|
||||
const uint8_t BPTCDeInterleavingIndex[196] =
|
||||
{
|
||||
0, 13, 26, 39,
|
||||
52, 65, 78, 91,
|
||||
104, 117, 130, 143,
|
||||
156, 169, 182, 195,
|
||||
12, 25, 38, 51,
|
||||
64, 77, 90, 103,
|
||||
116, 129, 142, 155,
|
||||
168, 181, 194, 11,
|
||||
24, 37, 50, 63,
|
||||
76, 89, 102, 115,
|
||||
128, 141, 154, 167,
|
||||
180, 193, 10, 23,
|
||||
36, 49, 62, 75,
|
||||
88, 101, 114, 127,
|
||||
140, 153, 166, 179,
|
||||
192, 9, 22, 35,
|
||||
48, 61, 74, 87,
|
||||
100, 113, 126, 139,
|
||||
152, 165, 178, 191,
|
||||
8, 21, 34, 47,
|
||||
60, 73, 86, 99,
|
||||
112, 125, 138, 151,
|
||||
164, 177, 190, 7,
|
||||
20, 33, 46, 59,
|
||||
72, 85, 98, 111,
|
||||
124, 137, 150, 163,
|
||||
176, 189, 6, 19,
|
||||
32, 45, 58, 71,
|
||||
84, 97, 110, 123,
|
||||
136, 149, 162, 175,
|
||||
188, 5, 18, 31,
|
||||
44, 57, 70, 83,
|
||||
96, 109, 122, 135,
|
||||
148, 161, 174, 187,
|
||||
4, 17, 30, 43,
|
||||
56, 69, 82, 95,
|
||||
108, 121, 134, 147,
|
||||
160, 173, 186, 3,
|
||||
16, 29, 42, 55,
|
||||
68, 81, 94, 107,
|
||||
120, 133, 146, 159,
|
||||
172, 185, 2, 15,
|
||||
28, 41, 54, 67,
|
||||
80, 93, 106, 119,
|
||||
132, 145, 158, 171,
|
||||
184, 1, 14, 27,
|
||||
40, 53, 66, 79,
|
||||
92, 105, 118, 131,
|
||||
144, 157, 170, 183
|
||||
};
|
||||
|
||||
|
||||
const uint8_t DeInterleaveReverseChannelBptc[32] =
|
||||
{
|
||||
0, 17, 2, 19, 4, 21, 6, 23,
|
||||
8, 25, 10, 27, 12, 29, 14, 31,
|
||||
16, 1, 18, 3, 20, 5, 22, 7,
|
||||
24, 9, 26, 11, 28, 13, 30, 15
|
||||
};
|
||||
|
||||
|
||||
/* Functions ----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function deinterleave the DMR data by using BPTC (196,96)
|
||||
*
|
||||
* @param Input : Pointer of DMR input data interleaved (196 bytes)
|
||||
*
|
||||
* @param Output : Pointer where DMR deinterleaved data will be written (196 bytes)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
|
||||
{
|
||||
uint32_t i, DeInterleaveIndex;
|
||||
|
||||
for(i = 0; i < 196; i++)
|
||||
{
|
||||
DeInterleaveIndex = BPTCDeInterleavingIndex[i];
|
||||
Output[DeInterleaveIndex] = (Input[i] & 1);
|
||||
}
|
||||
} /* End BPTCDeInterleaveDMRData() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 96 bits of a deinteleaved 196 bits
|
||||
* buffer using BPTC (196,96)
|
||||
*
|
||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (196 bytes)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (96 bytes)
|
||||
*
|
||||
* @return The total number of irrecoverable Hamming check errors
|
||||
*/
|
||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3])
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t DataMatrix[13][15];
|
||||
uint8_t LineUncorrected[15];
|
||||
uint8_t LineCorrected[11];
|
||||
uint8_t ColumnUncorrected[13];
|
||||
uint8_t ColumnCorrected[9];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
/* First step : Reconstitute the BPTC 15x11 matrix
|
||||
* Note : Input data shall be deinterleaved */
|
||||
k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
for(i = 0; i < 13; i++)
|
||||
{
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
/* Only the LSBit of the byte is stored */
|
||||
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* R(0) to R(2) may be used to transport some
|
||||
* Restricted Access System (RAS) information,
|
||||
* So save these three bytes before reset all of them
|
||||
* See patent US 2013/0288643 A1 */
|
||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
||||
|
||||
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
DataMatrix[0][0] = 0; /* R(2) */
|
||||
DataMatrix[0][1] = 0; /* R(1) */
|
||||
DataMatrix[0][2] = 0; /* R(0) */
|
||||
|
||||
/* Init the Hamming (15,11,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_15_11_init();
|
||||
|
||||
/* Init the Hamming (13,9,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_13_9_init();
|
||||
|
||||
/* Init the Hamming error counter */
|
||||
HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each line (first time).
|
||||
* Do not check the 4th last lines */
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each column/row (first time) */
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 13; j++)
|
||||
{
|
||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 9; j++)
|
||||
{
|
||||
DataMatrix[j][i] = ColumnCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* The first Hamming code check has maybe corrected bit
|
||||
* witch can be use to correct other bit, so make the
|
||||
* same operation twice */
|
||||
|
||||
/* Reset the number of irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each line (second time).
|
||||
* Do not check the 4th last lines */
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
/* Row/Line contains irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Row/Line contains correct data */
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each column/row (second time) */
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 13; j++)
|
||||
{
|
||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||
{
|
||||
/* Row/Line contains irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Row/Line contains correct data */
|
||||
}
|
||||
|
||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 9; j++)
|
||||
{
|
||||
DataMatrix[j][i] = ColumnCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the DMR data (96 bit) from the matrix */
|
||||
/* First line : Do not take R(2), R(1) and R(0) */
|
||||
k = 0;
|
||||
|
||||
for(i = 3; i < 11; i++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[0][i];
|
||||
k++;
|
||||
}
|
||||
|
||||
/* Next lines */
|
||||
for(i = 1; i < 9; i++)
|
||||
{
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors */
|
||||
return HammingIrrecoverableErrorNb;
|
||||
} /* End BPTC_196x96_Extract_Data() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 77 bits of a deinteleaved 128 bits
|
||||
* buffer using BPTC (128,77).
|
||||
*
|
||||
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.1 for details
|
||||
*
|
||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (128 bytes
|
||||
act as a 16 x 8 byte data matrix)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
|
||||
* DMRDataExtracted[0..71] = Util data (hamming corrected)
|
||||
* DMRDataExtracted[72..76] = 5 bit of CRC extracted (to be checked)
|
||||
*
|
||||
* @return 0 = All is OK
|
||||
* Other = Error - Irrecoverable Hamming parity check error number
|
||||
*/
|
||||
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77])
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t DataMatrix[8][16];
|
||||
uint8_t LineUncorrected[16];
|
||||
uint8_t LineCorrected[11];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
uint32_t ParityCheckErrorNb = 0;
|
||||
uint32_t NbOfOne;
|
||||
|
||||
/* First step : Reconstitute the BPTC 16x8 matrix */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
/* Only the LSBit of the byte is stored */
|
||||
DataMatrix[i][j] = (InputDataMatrix[i][j] & 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Init the Hamming (16,11,4) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_16_11_4_init();
|
||||
|
||||
/* Process the the Hamming (16,11,4) code
|
||||
* check on each line.
|
||||
* Do not check the last line (line nb 8) */
|
||||
for(i = 0; i < 7; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (16,11,4) code correction */
|
||||
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the DMR data (77 bit) from the matrix */
|
||||
k = 0;
|
||||
|
||||
/* 2 first lines */
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5 Next lines */
|
||||
for(i = 2; i < 7; i++)
|
||||
{
|
||||
for(j = 0; j < 10; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5 bit of CRC */
|
||||
for(i = 2; i < 7; i++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][10];
|
||||
k++;
|
||||
}
|
||||
|
||||
/* Verify the data integrity by checking
|
||||
* all column parity bit */
|
||||
ParityCheckErrorNb = 0;
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
NbOfOne = 0;
|
||||
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 7; j++)
|
||||
{
|
||||
NbOfOne += DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Check the parity bit (number of "1"
|
||||
* must be even) */
|
||||
if((NbOfOne % 2) != DataMatrix[7][i])
|
||||
{
|
||||
ParityCheckErrorNb++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
} /* End BPTC_128x77_Extract_Data() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 32 bits of a deinteleaved 32 bits
|
||||
* buffer using Reverse Channel Single Burst BPTC.
|
||||
*
|
||||
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.2.2 for details
|
||||
*
|
||||
* @param InputInterleavedData : Pointer of DMR input data interleaved (32 bytes
|
||||
act as a 16 x 2 bits data matrix)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
|
||||
* DMRDataExtracted[0..10] = Util data (Hamming corrected)
|
||||
* DMRDataExtracted[11..15] = Hamming data
|
||||
* DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked)
|
||||
*
|
||||
* @return 0 = All is OK
|
||||
* Other = Error - Irrecoverable Hamming parity check error number
|
||||
*/
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32])
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t DataMatrix[32];
|
||||
uint8_t LineUncorrected[16];
|
||||
uint8_t LineCorrected[11];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
uint32_t ParityCheckErrorNb = 0;
|
||||
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DataMatrix[DeInterleaveReverseChannelBptc[i]] = InputInterleavedData[i] & 1;
|
||||
}
|
||||
|
||||
/* Copy the entire input buffer to the output buffer */
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = DataMatrix[i];
|
||||
}
|
||||
|
||||
/* Prepare the line to be corrected */
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
LineUncorrected[i] = DataMatrix[i];
|
||||
}
|
||||
|
||||
/* Apply Hamming (16,11,4) code correction */
|
||||
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Copy the corrected content to the output buffer */
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = LineCorrected[i];
|
||||
}
|
||||
|
||||
/* Check Parity bits */
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
/* Odd parity ==> If data = 1 then parity = 0
|
||||
* If data = 0 then parity = 1 */
|
||||
if(DMRDataExtracted[i] == DMRDataExtracted[i + 16]) ParityCheckErrorNb++;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "Hamming ERR=%u ; Parity ERR=%u", HammingIrrecoverableErrorNb, ParityCheckErrorNb);
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
|
||||
} /* End BPTC_16x2_Extract_Data() */
|
||||
|
||||
|
||||
|
||||
/* End of file */
|
||||
515
src/dmr_data.c
515
src/dmr_data.c
@@ -24,240 +24,409 @@ 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) |");
|
||||
if(state->color_code_ok) fprintf(stderr, "(CRC OK ) |"); //add line break
|
||||
else fprintf(stderr, "(CRC ERR) |"); //add line break
|
||||
//fprintf (stderr, "\n"); //print line break
|
||||
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:
|
||||
{
|
||||
ProcessDmrPIHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = Voice LC header */
|
||||
case 0b0001:
|
||||
{
|
||||
/* Extract data from Voice LC Header */
|
||||
ProcessDmrVoiceLcHeader(opts, state, (uint8_t *)info, (uint8_t *)syncdata, (uint8_t *)SlotType);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Burst = TLC */
|
||||
case 0b0010:
|
||||
{
|
||||
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() */
|
||||
|
||||
113
src/dmr_encryption.c
Normal file
113
src/dmr_encryption.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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;
|
||||
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameL = NULL;
|
||||
TimeSlotVoiceSuperFrame_t * TSVoiceSupFrameR = NULL;
|
||||
|
||||
int *errs;
|
||||
int *errs2;
|
||||
int *errsR;
|
||||
int *errs2R;
|
||||
unsigned long long int k;
|
||||
k = 0;
|
||||
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
TSVoiceSupFrame = &state->TS1SuperFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
TSVoiceSupFrame = &state->TS2SuperFrame;
|
||||
}
|
||||
|
||||
TSVoiceSupFrameL = &state->TS1SuperFrame;
|
||||
TSVoiceSupFrameR = &state->TS2SuperFrame;
|
||||
//
|
||||
//
|
||||
//
|
||||
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);
|
||||
|
||||
//errs = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
|
||||
//errs2 = (int*)&(TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
|
||||
//state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
|
||||
//state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
|
||||
|
||||
//errsR = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs1[i]);
|
||||
//errs2R = (int*)&(TSVoiceSupFrameR->TimeSlotAmbeVoiceFrame[Frame].errs2[i]);
|
||||
//state->errs = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs1[i]; //correct placement
|
||||
//state->errs2 = TSVoiceSupFrame->TimeSlotAmbeVoiceFrame[Frame].errs2[i]; //correct placement
|
||||
//state->audio_out_temp_bufR = state->audio_out_temp_buf;
|
||||
//mbe_processAmbe2450Dataf (state->audio_out_temp_buf, errs, errs2, state->err_str,
|
||||
// TSVoiceSupFrameL->TimeSlotAmbeVoiceFrame[Frame].AmbeBit[i],
|
||||
// state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
|
||||
//mbe_processAmbe2450Dataf (state->audio_out_temp_bufR, errsR, errs2R, state->err_strR,
|
||||
// TSVoiceSupFrameR->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;
|
||||
//state->debug_audio_errors += *errs2R;
|
||||
|
||||
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 */
|
||||
938
src/dmr_sync.c
Normal file
938
src/dmr_sync.c
Normal file
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* 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 ProcessDmrPIHeader(dsd_opts * opts, dsd_state * state, uint8_t info[196], uint8_t syncdata[48], uint8_t SlotType[20])
|
||||
{
|
||||
//Placeholder
|
||||
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++)
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
CRCExtracted = CRCExtracted << 1;
|
||||
//CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 72] & 1);
|
||||
CRCExtracted = CRCExtracted | (uint32_t)(DmrDataBit[i + 80] & 1); //80-96 for PI header
|
||||
}
|
||||
|
||||
//Look into whether or not we need to run these CRC checks for this header information
|
||||
//and see if its applied the same or differently
|
||||
/* Apply the CRC mask (see DMR standard B.3.12 Data Type CRC Mask) */
|
||||
//CRCExtracted = CRCExtracted ^ 0x969696; //does this mask get applied here though for PI?
|
||||
//CRCExtracted = CRCExtracted ^ 0x6969;
|
||||
|
||||
/* Check/correct the full link control data and compute the Reed-Solomon (12,9) CRC */
|
||||
//CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x969696);
|
||||
//CRCCorrect = ComputeAndCorrectFullLinkControlCrc(DmrDataByte, &CRCComputed, 0x6969);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
state->payload_algid = DmrDataByte[0];
|
||||
state->payload_keyid = DmrDataByte[2];
|
||||
state->payload_mi = ( ((DmrDataByte[3]) << 24) + ((DmrDataByte[4]) << 16) + ((DmrDataByte[5]) << 8) + (DmrDataByte[6]) );
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
fprintf (stderr, "\n DMR PI Header ALG ID: 0x%02X KEY ID: 0x%02X MI: 0x%08X", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
//fprintf (stderr, "\nDDB = 0x%X \n", DmrDataBit);
|
||||
/* 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, "\n 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, "(CRC 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;
|
||||
}
|
||||
//fprintf (stderr, "\nDDB = 0x%X \n", DmrDataBit);
|
||||
/* 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;
|
||||
//TSVoiceSupFrame->FullLC.LeftOvers = (unsigned int)ConvertBitIntoBytes(&DmrDataBit[64], 8);
|
||||
//fprintf (stderr, "\nBPTC Left Overs = %02X \n", TSVoiceSupFrame->FullLC.LeftOvers);
|
||||
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, "\n 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, "(CRC 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;
|
||||
//fprintf (stderr, "\nLCDB = 0x%X \n", LC_DataBit);
|
||||
/* 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, "(CRC 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 */
|
||||
882
src/dmr_voice.c
882
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->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
|
||||
|
||||
mbe_demodulateAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS1SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
|
||||
&(state->TS1SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 3 x 49 bit of AMBE sample per voice frame => Slot 2 buffer here */
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i] = mbe_eccAmbe3600x2450C0(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] = state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs1[i];
|
||||
|
||||
mbe_demodulateAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i]);
|
||||
state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].errs2[i] += mbe_eccAmbe3600x2450Data(state->TS2SuperFrame.TimeSlotDeinterleavedVoiceFrame[j].DeInterleavedVoiceSample[i],
|
||||
&(state->TS2SuperFrame.TimeSlotAmbeVoiceFrame[j].AmbeBit[i][0]));
|
||||
}
|
||||
|
||||
}
|
||||
} /* End for(j = 0; j < 6; j++) */
|
||||
|
||||
if(opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "%s %s ", state->slot1light, state->slot2light);
|
||||
|
||||
/* Print the color code */
|
||||
fprintf(stderr, "| Color Code=%02d ", (int)state->color_code);
|
||||
|
||||
//if(state->color_code_ok) fprintf(stderr, "(OK) |");
|
||||
if(state->color_code_ok) fprintf(stderr, "(CRC OK ) |"); //add line break
|
||||
else fprintf(stderr, "(CRC ERR) |"); //add line break
|
||||
|
||||
//fprintf(stderr, " VOICE e: \n");
|
||||
fprintf(stderr, " VOICE \n");
|
||||
}
|
||||
|
||||
/* Perform the SYNC DMR data embedded decoding */
|
||||
ProcessVoiceBurstSync(opts, state);
|
||||
|
||||
/* Perform the DMR encryption decoding */
|
||||
ProcessDMREncryption(opts, state);
|
||||
|
||||
/* Print DMR frame (if needed) */
|
||||
//DMRVoiceFrameProcess(opts, state); //HERE HERE, was enabled, disabled so I could build
|
||||
|
||||
if(opts->errorbars == 1)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
} /* End processDMRvoice() */
|
||||
|
||||
278
src/dpmr_data.c
Normal file
278
src/dpmr_data.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
|
||||
/* Convert the Channel code (24 bit) into a valid
|
||||
* dPMR color code [0..63]
|
||||
* Return -1 on error */
|
||||
int32_t GetdPmrColorCode(uint8_t ChannelCodeBit[24])
|
||||
{
|
||||
uint32_t ChannelCodeByte;
|
||||
int32_t ColorCode;
|
||||
uint32_t i;
|
||||
|
||||
/* Reconstitute the 24 bit channel code into a 3 bytes integer */
|
||||
ChannelCodeByte = 0;
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
ChannelCodeByte <<= 1;
|
||||
ChannelCodeByte |= (ChannelCodeBit[i] & 1);
|
||||
}
|
||||
|
||||
/* By analyzing all channel code on the
|
||||
* dPMR standard, I observe that if we decompose the
|
||||
* 24 bit into 12 dibit, all dibit's LSB are always
|
||||
* equal to "1", so apply a mask to correct
|
||||
* flipped LSB dibit.
|
||||
*
|
||||
* For more details see ETSI TS 102 658 chapter
|
||||
* 6.1.5.2.2 "Channel Code Determined by Frequency
|
||||
* and System Identity Code".
|
||||
*
|
||||
* Apply the mask 0x555555
|
||||
* 0x555555 = 0b010101010101010101010101 => All dibit's LSB
|
||||
* are equal to "1".
|
||||
*/
|
||||
ChannelCodeByte |= 0x555555;
|
||||
|
||||
|
||||
/* Switch to the right color code */
|
||||
switch(ChannelCodeByte & 0xFF0000)
|
||||
{
|
||||
case 0x570000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x575F77: {ColorCode = 0; break;}
|
||||
case 0x577577: {ColorCode = 1; break;}
|
||||
case 0x57DD75: {ColorCode = 2; break;}
|
||||
case 0x57F775: {ColorCode = 3; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x570000 */
|
||||
|
||||
case 0x550000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x55577D: {ColorCode = 4; break;}
|
||||
case 0x557D7D: {ColorCode = 5; break;}
|
||||
case 0x55D57F: {ColorCode = 6; break;}
|
||||
case 0x55FF7F: {ColorCode = 7; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x550000 */
|
||||
|
||||
case 0x5F0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x5F555F: {ColorCode = 8; break;}
|
||||
case 0x5F7F5F: {ColorCode = 9; break;}
|
||||
case 0x5FD75D: {ColorCode = 10; break;}
|
||||
case 0x5FFD5D: {ColorCode = 11; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x5F0000 */
|
||||
|
||||
case 0x5D0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x5D5D55: {ColorCode = 12; break;}
|
||||
case 0x5D7755: {ColorCode = 13; break;}
|
||||
case 0x5DDF57: {ColorCode = 14; break;}
|
||||
case 0x5DF557: {ColorCode = 15; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x5D0000 */
|
||||
|
||||
case 0x770000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x775DD7: {ColorCode = 16; break;}
|
||||
case 0x7777D7: {ColorCode = 17; break;}
|
||||
case 0x77DFD5: {ColorCode = 18; break;}
|
||||
case 0x77F5D5: {ColorCode = 19; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x770000 */
|
||||
|
||||
case 0x750000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x7555DD: {ColorCode = 20; break;}
|
||||
case 0x757FDD: {ColorCode = 21; break;}
|
||||
case 0x75D7DF: {ColorCode = 22; break;}
|
||||
case 0x75FDDF: {ColorCode = 23; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x750000 */
|
||||
|
||||
case 0x7F0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x7F57FF: {ColorCode = 24; break;}
|
||||
case 0x7F7DFF: {ColorCode = 25; break;}
|
||||
case 0x7FD5FD: {ColorCode = 26; break;}
|
||||
case 0x7FFFFD: {ColorCode = 27; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x7F0000 */
|
||||
|
||||
case 0x7D0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0x7D5FF5: {ColorCode = 28; break;}
|
||||
case 0x7D75F5: {ColorCode = 29; break;}
|
||||
case 0x7DDDF7: {ColorCode = 30; break;}
|
||||
case 0x7DF7F7: {ColorCode = 31; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0x7D0000 */
|
||||
|
||||
case 0xD70000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xD755F7: {ColorCode = 32; break;}
|
||||
case 0xD77FF7: {ColorCode = 33; break;}
|
||||
case 0xD7D7F5: {ColorCode = 34; break;}
|
||||
case 0xD7FDF5: {ColorCode = 35; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xD70000 */
|
||||
|
||||
case 0xD50000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xD55DFD: {ColorCode = 36; break;}
|
||||
case 0xD577FD: {ColorCode = 37; break;}
|
||||
case 0xD5DFFF: {ColorCode = 38; break;}
|
||||
case 0xD5F5FF: {ColorCode = 39; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xD50000 */
|
||||
|
||||
case 0xDF0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xDF5FDF: {ColorCode = 40; break;}
|
||||
case 0xDF75DF: {ColorCode = 41; break;}
|
||||
case 0xDFDDDD: {ColorCode = 42; break;}
|
||||
case 0xDFF7DD: {ColorCode = 43; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xDF0000 */
|
||||
|
||||
case 0xDD0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xDD57D5: {ColorCode = 44; break;}
|
||||
case 0xDD7DD5: {ColorCode = 45; break;}
|
||||
case 0xDDD5D7: {ColorCode = 46; break;}
|
||||
case 0xDDFFD7: {ColorCode = 47; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xDD0000 */
|
||||
|
||||
case 0xF70000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xF75757: {ColorCode = 48; break;}
|
||||
case 0xF77D57: {ColorCode = 49; break;}
|
||||
case 0xF7D555: {ColorCode = 50; break;}
|
||||
case 0xF7FF55: {ColorCode = 51; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xF70000 */
|
||||
|
||||
case 0xF50000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xF55F5D: {ColorCode = 52; break;}
|
||||
case 0xF5755D: {ColorCode = 53; break;}
|
||||
case 0xF5DD5F: {ColorCode = 54; break;}
|
||||
case 0xF5F75F: {ColorCode = 55; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xF50000 */
|
||||
|
||||
case 0xFF0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xFF5D7F: {ColorCode = 56; break;}
|
||||
case 0xFF777F: {ColorCode = 57; break;}
|
||||
case 0xFFDF7D: {ColorCode = 58; break;}
|
||||
case 0xFFF57D: {ColorCode = 59; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xFF0000 */
|
||||
|
||||
case 0xFD0000:
|
||||
{
|
||||
switch(ChannelCodeByte)
|
||||
{
|
||||
case 0xFD5575: {ColorCode = 60; break;}
|
||||
case 0xFD7F75: {ColorCode = 61; break;}
|
||||
case 0xFDD777: {ColorCode = 62; break;}
|
||||
case 0xFDFD77: {ColorCode = 63; break;}
|
||||
default: {ColorCode = -1; break;}
|
||||
} /* End switch(ChannelCodeByte) */
|
||||
break;
|
||||
} /* End case 0xFD0000 */
|
||||
|
||||
default:
|
||||
{
|
||||
ColorCode = -1;
|
||||
break;
|
||||
}
|
||||
} /* End switch(ChannelCodeByte & 0xFF0000) */
|
||||
|
||||
/* Return the colour code */
|
||||
return ColorCode;
|
||||
}
|
||||
|
||||
|
||||
/* End of file */
|
||||
941
src/dpmr_voice.c
Normal file
941
src/dpmr_voice.c
Normal file
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[0], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[1], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[2], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[3], NULL); //HERE HERE
|
||||
|
||||
/* 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
|
||||
//ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
//ambe_fr2[*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++;
|
||||
}
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[j], NULL);
|
||||
|
||||
#ifdef DPMR_DUMP
|
||||
fprintf(stderr, " ");
|
||||
#endif
|
||||
}
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[4], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[5], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[6], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[7], NULL); //HERE HERE
|
||||
|
||||
#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, "\n| 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++)
|
||||
//for(i = 0; i < (8); 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]);
|
||||
mbe_demodulateAmbe3600x2400Data(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]);
|
||||
state->dPMRVoiceFS2Frame.errs2[i] += (unsigned int)mbe_eccAmbe3600x2400Data(ambe_fr[i], (char *)state->dPMRVoiceFS2Frame.AmbeBit[i]);
|
||||
//processMbeFrame (opts, state, NULL, ambe_fr[i], NULL); //HERE HERE
|
||||
//processMbeFrame (opts, state, NULL, state->dPMRVoiceFS2Frame.AmbeBit[i], NULL); //HERE HERE
|
||||
}
|
||||
} /* 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++) //is this backwards, shouldn't we run this first, and then voice frame after?
|
||||
{
|
||||
|
||||
//errs = (uint32_t*)&(state->dPMRVoiceFS2Frame.errs1[i]);
|
||||
errs2 = (uint32_t*)&(state->dPMRVoiceFS2Frame.errs2[i]);
|
||||
errs = 0;
|
||||
//errs2 = 0;
|
||||
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
|
||||
//could be related to err states not properly done or something?
|
||||
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);
|
||||
|
||||
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 */
|
||||
@@ -21,28 +21,35 @@ pa_sample_spec ss;
|
||||
pa_sample_spec tt;
|
||||
pa_sample_spec zz;
|
||||
pa_sample_spec cc;
|
||||
//pa_channel_map channel_map;
|
||||
|
||||
|
||||
void openPulseOutput(dsd_opts * opts)
|
||||
{
|
||||
|
||||
//ss.format = PA_SAMPLE_S16NE;
|
||||
//ss.channels = opts->pulse_raw_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||
//ss.rate = opts->pulse_raw_rate_out; //48000
|
||||
ss.format = PA_SAMPLE_S16NE;
|
||||
ss.channels = opts->pulse_raw_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||
ss.rate = opts->pulse_raw_rate_out; //48000
|
||||
|
||||
tt.format = PA_SAMPLE_S16NE;
|
||||
tt.channels = opts->pulse_digi_out_channels; //doing tests with 2 channels at 22050 for 44100 audio default in pulse
|
||||
tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle
|
||||
//fprintf (stderr,"digi rate out = %d\n", opts->pulse_digi_rate_out);
|
||||
|
||||
//pa_channel_map_init_stereo(&channel_map);
|
||||
//ss
|
||||
if (opts->monitor_input_audio == 1)
|
||||
{
|
||||
//opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
|
||||
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
//tt
|
||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out", &tt, NULL, NULL, NULL);
|
||||
|
||||
pa_channel_map* left = 0; //NULL and 0 are same in this context
|
||||
pa_channel_map* right = 0; //NULL and 0 are same in this context
|
||||
//pa_channel_map* right;
|
||||
//pa_channel_map_init(right);
|
||||
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, left, NULL, NULL);
|
||||
//opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out LEFT", &tt, left, NULL, NULL);
|
||||
//opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out RIGHT", &tt, right, NULL, NULL);
|
||||
}
|
||||
|
||||
void openPulseInput(dsd_opts * opts)
|
||||
@@ -57,12 +64,12 @@ void openPulseInput(dsd_opts * opts)
|
||||
cc.rate = opts->pulse_digi_rate_in; //48000
|
||||
|
||||
//zz
|
||||
if (opts->monitor_input_audio == 2)
|
||||
if (opts->monitor_input_audio == 1)
|
||||
{
|
||||
//opts->pulse_raw_dev_in = pa_simple_new(NULL, "DSD FME", PA_STREAM_RECORD, NULL, "Raw Audio In", &zz, NULL, NULL, NULL);
|
||||
}
|
||||
//cc
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD FME", PA_STREAM_RECORD, NULL, "Audio In", &cc, NULL, NULL, NULL);
|
||||
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, opts->output_name, &cc, NULL, NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
@@ -161,6 +168,7 @@ processAudio (dsd_opts * opts, dsd_state * state)
|
||||
// detect max level
|
||||
max = 0;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
//state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
aout_abs = fabsf (*state->audio_out_temp_buf_p);
|
||||
@@ -169,15 +177,24 @@ processAudio (dsd_opts * opts, dsd_state * state)
|
||||
max = aout_abs;
|
||||
}
|
||||
state->audio_out_temp_buf_p++;
|
||||
//state->audio_out_temp_buf_pR++;
|
||||
}
|
||||
*state->aout_max_buf_p = max;
|
||||
//*state->aout_max_buf_pR = max;
|
||||
state->aout_max_buf_p++;
|
||||
//state->aout_max_buf_pR++;
|
||||
state->aout_max_buf_idx++;
|
||||
//state->aout_max_buf_idxR++;
|
||||
if (state->aout_max_buf_idx > 24)
|
||||
{
|
||||
state->aout_max_buf_idx = 0;
|
||||
state->aout_max_buf_p = state->aout_max_buf;
|
||||
}
|
||||
//if (state->aout_max_buf_idxR > 24)
|
||||
// {
|
||||
// state->aout_max_buf_idxR = 0;
|
||||
// state->aout_max_buf_pR = state->aout_max_bufR;
|
||||
// }
|
||||
|
||||
// lookup max history
|
||||
for (i = 0; i < 25; i++)
|
||||
@@ -412,6 +429,20 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
//pa_simple_write(opts->pulse_raw_dev_out, (void*)&state->pulse_raw_out_buffer, 2, NULL);
|
||||
|
||||
}
|
||||
|
||||
//two slot audio testing, still need to seperate channels first internally, but this will play them out of different streams
|
||||
/*
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works.
|
||||
}
|
||||
if(state->currentslot == 1)
|
||||
{
|
||||
pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works.
|
||||
//pa_simple_write(opts->pulse_raw_dev_out, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL); //Yay! It works.
|
||||
}
|
||||
*/
|
||||
|
||||
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works.
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
|
||||
@@ -444,6 +444,9 @@ get_dibit_and_analog_signal (dsd_opts* opts, dsd_state* state, int* out_analog_s
|
||||
|
||||
//
|
||||
state->sbuf[state->sidx] = symbol;
|
||||
//
|
||||
//state->pulse_raw_out_buffer = symbol;
|
||||
//
|
||||
if (out_analog_signal != NULL)
|
||||
{
|
||||
*out_analog_signal = symbol;
|
||||
|
||||
@@ -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++) //using 7 seems to break older amb files where it was 6, need to test 7 on 7 some more
|
||||
{
|
||||
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++) //breaks backwards compatablilty with 6 files
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -31,7 +31,7 @@ printFrameInfo (dsd_opts * opts, dsd_state * state)
|
||||
level = (int) state->max / 164;
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
if (state->nac != 0)
|
||||
{
|
||||
@@ -89,7 +89,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr, "inlvl: %2i%% ", level);
|
||||
//fprintf (stderr, "inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
@@ -112,7 +112,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr, "inlvl: %2i%% ", level);
|
||||
//fprintf (stderr, "inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
@@ -134,7 +134,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
@@ -156,7 +156,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
@@ -179,7 +179,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ((state->synctype == 11) || (state->synctype == 12))
|
||||
@@ -233,7 +233,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) state->max / 164;
|
||||
fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
//fprintf (stderr,"inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
@@ -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
|
||||
@@ -565,7 +609,8 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
fprintf (stderr," duid:%s *Unknown DUID*\n", duid);
|
||||
//fprintf (stderr," duid:%s *Unknown DUID*\n", duid); //prints on dPMR frame 3
|
||||
fprintf (stderr, "\n"); //prints on dPMR frame 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
126
src/dsd_main.c
126
src/dsd_main.c
@@ -95,6 +95,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->min = -15000;
|
||||
state->center = 0;
|
||||
state->err_str[0] = 0;
|
||||
state->err_strR[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
sprintf (state->ftype, " ");
|
||||
state->errs = 0;
|
||||
@@ -162,12 +163,13 @@ initOpts (dsd_opts * opts)
|
||||
opts->serial_baud = 115200;
|
||||
sprintf (opts->serial_dev, "/dev/ttyUSB0");
|
||||
opts->resume = 0;
|
||||
opts->frame_dstar = 0;
|
||||
opts->frame_dstar = 1; //was disabled for some reason, make sure there are no false positives
|
||||
opts->frame_x2tdma = 1;
|
||||
opts->frame_p25p1 = 1;
|
||||
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 +192,20 @@ 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_out = 24000; //need to copy this to rtl type in and change rate out to 8000
|
||||
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_raw_in_channels = 1;
|
||||
opts->pulse_raw_out_channels = 1;
|
||||
opts->pulse_digi_in_channels = 2;
|
||||
opts->pulse_digi_out_channels = 2;
|
||||
opts->pulse_digi_in_channels = 1; //2
|
||||
opts->pulse_digi_out_channels = 1; //2
|
||||
|
||||
sprintf (opts->output_name, "Auto Detect");
|
||||
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->use_ncurses_terminal = 0;
|
||||
opts->payload = 0;
|
||||
|
||||
opts->EncryptionMode = MODE_UNENCRYPTED;
|
||||
opts->inverted_dpmr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -213,14 +219,23 @@ initState (dsd_state * state)
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->repeat = 0;
|
||||
state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
||||
state->audio_out_bufR = malloc (sizeof (short) * 1000000);
|
||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
state->audio_out_buf_pR = state->audio_out_buf + 100;
|
||||
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
|
||||
state->audio_out_float_bufR = malloc (sizeof (float) * 1000000);
|
||||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
state->audio_out_idx = 0;
|
||||
state->audio_out_idx2 = 0;
|
||||
state->audio_out_idxR = 0;
|
||||
state->audio_out_idx2R = 0;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
|
||||
//state->wav_out_bytes = 0;
|
||||
state->center = 0;
|
||||
state->jitter = -1;
|
||||
@@ -247,6 +262,7 @@ initState (dsd_state * state)
|
||||
}
|
||||
state->midx = 0;
|
||||
state->err_str[0] = 0;
|
||||
state->err_strR[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
sprintf (state->ftype, " ");
|
||||
state->symbolcnt = 0;
|
||||
@@ -296,6 +312,21 @@ initState (dsd_state * state)
|
||||
|
||||
state->nxdn_last_ran = -1;
|
||||
state->nxdn_last_rid = 0;
|
||||
state->nxdn_last_tg = 0;
|
||||
state->nxdn_cipher_type = 0;
|
||||
state->nxdn_key = 0;
|
||||
sprintf (state->nxdn_call_type, " ");
|
||||
|
||||
state->dpmr_color_code = -1;
|
||||
state->dpmr_caller_id = 0;
|
||||
state->dpmr_target_id = 0;
|
||||
|
||||
state->payload_mi = 0;
|
||||
state->payload_mfid = 0;
|
||||
state->payload_algid = 0;
|
||||
state->payload_keyid = 0;
|
||||
|
||||
state->K = 0;
|
||||
|
||||
#ifdef TRACE_DSD
|
||||
state->debug_sample_index = 0;
|
||||
@@ -357,11 +388,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 +403,7 @@ usage ()
|
||||
fprintf (stderr," -u <num> Unvoiced speech quality (default=3)\n");
|
||||
fprintf (stderr," -xx Expect non-inverted X2-TDMA signal\n");
|
||||
fprintf (stderr," -xr Expect inverted DMR/MOTOTRBO signal\n");
|
||||
fprintf (stderr," -xd Expect inverted ICOM dPMR signal\n"); //still need to do this
|
||||
fprintf (stderr,"\n");
|
||||
fprintf (stderr," * denotes frame types that cannot be auto-detected.\n");
|
||||
fprintf (stderr,"\n");
|
||||
@@ -619,10 +652,12 @@ main (int argc, char **argv)
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
|
||||
InitAllFecFunction(); //HERE
|
||||
|
||||
exitflag = 0;
|
||||
signal (SIGINT, sigfun);
|
||||
|
||||
while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:Y:NWrlZ")) != -1)
|
||||
while ((c = getopt (argc, argv, "haep:P:qstv:z:i:o:d:c:g:nw:B:C:R:f:m:u:x:A:S:M:G:D:L:V:U:Y:K:NWrlZ")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
@@ -685,6 +720,11 @@ main (int argc, char **argv)
|
||||
sscanf (optarg, "%d", &opts.verbose);
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
sscanf (optarg, "%lld", &state.K);
|
||||
state.K = ( ((state.K & 0xFF0F) << 32 ) + (state.K << 16) + state.K );
|
||||
break;
|
||||
|
||||
case 'G': //Set rtl device gain
|
||||
sscanf (optarg, "%d", &opts.rtl_gain_value); //multiple value by ten to make it consitent with the way rtl_fm really works
|
||||
break;
|
||||
@@ -710,10 +750,19 @@ main (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'W': //monitor_input_audio if no sync
|
||||
opts.monitor_input_audio = 0;
|
||||
//fprintf (stderr,"Monitor Source Audio Enabled (WIP!) Sounds bad.\n");
|
||||
//fprintf (stderr,"Monitor Source Audio may cause decoding issues.\n");
|
||||
fprintf (stderr,"Monitor Source Audio currently disabled in Pulse Audio Builds.\n");
|
||||
opts.monitor_input_audio = 1;
|
||||
fprintf (stderr,"Monitor Source Audio Enabled.\n");
|
||||
//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 = 48000;
|
||||
//opts.pulse_digi_rate_out = 48000; //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 = 1; //2
|
||||
//opts.pulse_digi_out_channels = 1; //2
|
||||
fprintf (stderr," Monitor Source Audio may cause decoding issues.\n");
|
||||
fprintf (stderr," Don't Run Monitor Source Audio with Ncurses Terminal.\n");
|
||||
opts.use_ncurses_terminal = 0; //may not set depends on when -N and -W are first and second
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
@@ -807,7 +856,9 @@ 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
|
||||
sprintf (opts.output_name, "Auto Detect");
|
||||
}
|
||||
else if (optarg[0] == 'd')
|
||||
{
|
||||
@@ -817,7 +868,9 @@ 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;
|
||||
sprintf (opts.output_name, "D-STAR");
|
||||
fprintf (stderr,"Decoding only D-STAR frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'x')
|
||||
@@ -828,7 +881,9 @@ 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;
|
||||
sprintf (opts.output_name, "X2-TDMA");
|
||||
fprintf (stderr,"Decoding only X2-TDMA frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'p')
|
||||
@@ -839,6 +894,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;
|
||||
@@ -846,6 +902,7 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 2;
|
||||
sprintf (opts.output_name, "ProVoice");
|
||||
fprintf (stderr,"Setting symbol rate to 9600 / second\n");
|
||||
fprintf (stderr,"Enabling only GFSK modulation optimizations.\n");
|
||||
fprintf (stderr,"Decoding only ProVoice frames.\n");
|
||||
@@ -858,11 +915,13 @@ 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?
|
||||
opts.mod_qpsk = 0;
|
||||
state.rf_mod = 0; //
|
||||
sprintf (opts.output_name, "P25P1");
|
||||
fprintf (stderr,"Decoding only P25 Phase 1 frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'i')
|
||||
@@ -873,6 +932,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;
|
||||
@@ -881,6 +941,7 @@ main (int argc, char **argv)
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0; //was 1 with others on zero
|
||||
state.rf_mod = 0; //was 2
|
||||
sprintf (opts.output_name, "NXDN48");
|
||||
//opts.symboltiming = 2400; //NXDN48 uses 2400 symbol rate
|
||||
fprintf (stderr,"Setting symbol rate to 2400 / second\n");
|
||||
fprintf (stderr,"Enabling only C4FM modulation optimizations.\n");
|
||||
@@ -894,11 +955,13 @@ 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;
|
||||
opts.mod_gfsk = 0; //was 1
|
||||
state.rf_mod = 0; //was 2
|
||||
sprintf (opts.output_name, "NXDN96");
|
||||
fprintf (stderr,"Enabling only C4FM modulation optimizations.\n");
|
||||
fprintf (stderr,"Decoding only NXDN 9600 baud frames.\n");
|
||||
}
|
||||
@@ -910,13 +973,42 @@ 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;
|
||||
opts.mod_gfsk = 0; //
|
||||
state.rf_mod = 0; //
|
||||
sprintf (opts.output_name, "DMR/MOTOTRBO");
|
||||
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; //garbage value to keep jitter in check?
|
||||
sprintf (opts.output_name, "dPMR");
|
||||
//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 +1066,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);
|
||||
@@ -1007,6 +1104,7 @@ main (int argc, char **argv)
|
||||
opts.playfiles = 1;
|
||||
opts.errorbars = 0;
|
||||
opts.datascope = 0;
|
||||
sprintf (opts.output_name, "MBE Playback");
|
||||
state.optind = optind;
|
||||
break;
|
||||
case 'l':
|
||||
|
||||
@@ -31,12 +31,13 @@
|
||||
int reset = 0;
|
||||
char c; //getch key
|
||||
int tg; //last tg
|
||||
int tgn;
|
||||
int rd; //last rid
|
||||
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 +54,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 +74,15 @@ char * SyncTypes[20] = {
|
||||
"+NXDN DATA", //16
|
||||
"-NXDN DATA", //17
|
||||
"+DSTAR HD",
|
||||
"-DSTAR HD"
|
||||
"-DSTAR HD",
|
||||
"+dPMR",
|
||||
"+dPMR",
|
||||
"+dPMR",
|
||||
"+dPMR",
|
||||
"-dPMR",
|
||||
"-dPMR",
|
||||
"-dPMR",
|
||||
"-dPMR"
|
||||
|
||||
};
|
||||
|
||||
@@ -180,14 +189,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
call_matrix[9][1] = rn;
|
||||
call_matrix[9][2] = src;
|
||||
call_matrix[9][3] = 0;
|
||||
call_matrix[9][4] = 0;
|
||||
call_matrix[9][4] = tgn;
|
||||
call_matrix[9][5] = time(NULL);
|
||||
|
||||
}
|
||||
|
||||
//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++)
|
||||
@@ -244,7 +253,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
if (opts->audio_in_type == 3)
|
||||
{
|
||||
printw ("| RTL2838 Device #[%d]", opts->rtl_dev_index);
|
||||
printw ("| RTL2838UHIDIR Device #[%d]", opts->rtl_dev_index);
|
||||
printw (" Gain [%i] dB -", opts->rtl_gain_value);
|
||||
printw (" Squelch [%i]", opts->rtl_squelch_level);
|
||||
printw (" VFO [%i] kHz\n", opts->rtl_bandwidth);
|
||||
@@ -270,12 +279,12 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (state->carrier == 1){ //figure out method that will tell me when is active and when not active, maybe carrier but this doesn't print anyways unless activity
|
||||
attron(COLOR_PAIR(3));
|
||||
level = (int) state->max / 164; //only update on carrier present
|
||||
reset = 1;
|
||||
//reset = 1;
|
||||
}
|
||||
if (state->carrier == 0 && opts->reset_state == 1 && reset == 1)
|
||||
{
|
||||
resetState (state);
|
||||
reset = 0;
|
||||
//resetState (state);
|
||||
//reset = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,6 +296,16 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
|
||||
printw ("--Call Info-------------------------------------------------------------------\n");
|
||||
//NXDN Ciper Types
|
||||
//switch(CipherType)
|
||||
//{
|
||||
// case 0: Ptr = ""; break; /* Non-ciphered mode / clear call */
|
||||
// case 1: Ptr = "Scrambler"; break;
|
||||
// case 2: Ptr = "DES"; break;
|
||||
// case 3: Ptr = "AES"; break;
|
||||
// default: Ptr = "Unknown Cipher Type"; break;
|
||||
//}
|
||||
|
||||
if (state->lastsynctype != -1) //not sure if this will be okay
|
||||
{
|
||||
lls = state->lastsynctype;
|
||||
@@ -294,44 +313,94 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (state->nxdn_last_rid > 0 && state->nxdn_last_rid != src);
|
||||
{
|
||||
src = state->nxdn_last_rid;
|
||||
//rn = state->nxdn_last_ran;
|
||||
}
|
||||
if (state->nxdn_last_ran > -1 && state->nxdn_last_ran != rn);
|
||||
{
|
||||
//src = state->nxdn_last_rid;
|
||||
rn = state->nxdn_last_ran;
|
||||
}
|
||||
if (state->nxdn_last_tg > 0 && state->nxdn_last_tg != tgn);
|
||||
{
|
||||
tgn = state->nxdn_last_tg;
|
||||
}
|
||||
|
||||
//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
|
||||
|
||||
if (state->dmr_color_code > 0 && (lls == 10 || lls == 11 || lls == 12 || lls == 13) ) //DMR, DCC only carried on Data?
|
||||
{
|
||||
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
|
||||
if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
|
||||
{
|
||||
//printw ("| RAN: [%02d] \n", state->nxdn_last_ran);
|
||||
printw ("| RAN: [%02d] \n", rn);
|
||||
printw ("| RID: [%d] \n", src); //maybe change to nxdn_last_rid
|
||||
printw ("| RAN: [%2d] ", rn);
|
||||
printw ("TID: [%4d] ", tgn);
|
||||
//printw ("| RID: [%d] \n", src);
|
||||
printw ("RID: [%4d] \n| ALG: [0x%02X] KEY [0x%02X] ", src, state->nxdn_cipher_type, state->nxdn_key);
|
||||
if (state->carrier == 1)
|
||||
{
|
||||
printw("%s ", state->nxdn_call_type);
|
||||
//attron(COLOR_PAIR(4));
|
||||
//printw ("No Encryption ");
|
||||
//attroff(COLOR_PAIR(4));
|
||||
//attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0x1 && state->carrier == 1)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("Scrambler Encryption ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0x2 && state->carrier == 1)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("DES Encryption ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->nxdn_cipher_type == 0x3 && state->carrier == 1)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("AES Encryption ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if (state->nxdn_cipher_type > 0x3 && state->carrier == 1)
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw ("Unknown Encryption ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
//printw("%s ", state->nxdn_call_type);
|
||||
printw("\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
//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;
|
||||
@@ -340,8 +409,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
//printw("| TID:[%i] | RID:[%i] \n", tg, rd);
|
||||
//printw("| NAC: [0x%X] \n", nc);
|
||||
printw("| TID:[%i] RID:[%i] ", tg, rd);
|
||||
printw("NAC: [0x%X] \n", nc);
|
||||
printw("| TID:[%8i] RID:[%8i] ", tg, rd);
|
||||
printw("NAC: [0x%3X] \n", nc);
|
||||
printw("| ALG: [0x%02X] ", state->payload_algid);
|
||||
printw("KEY: [0x%04X] ", state->payload_keyid);
|
||||
//printw("MFG: [0x%X] ", state->payload_mfid); //no way of knowing if this is accurate info yet
|
||||
@@ -358,9 +427,67 @@ 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);
|
||||
//attron(COLOR_PAIR(3));
|
||||
printw ("| DCC: [%2i] FID: [%02X] SOP: [%02X] ", dcc, state->dmr_fid, state->dmr_so);
|
||||
if(state->payload_mi == 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
attron(COLOR_PAIR(5));
|
||||
printw ("**BP** ");
|
||||
//printw ("0x%X", state->payload_algid);
|
||||
attroff(COLOR_PAIR(5));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if(state->payload_keyid > 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
attron(COLOR_PAIR(5));
|
||||
printw (" ALG: [0x%02X] KEY [0x%02X] MI [0x%08X]", state->payload_algid, state->payload_keyid, state->payload_mi);
|
||||
//printw ("0x%X", state->payload_algid);
|
||||
attroff(COLOR_PAIR(5));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
if(state->K > 0 && state->dmr_so & 0x40)
|
||||
{
|
||||
attron(COLOR_PAIR(5));
|
||||
//printw ("K 0x[%12llX]", state->K); //seems to get reset in ncurses for some reason? some bigger issue perhaps? other strange issues occur too with provoice
|
||||
attroff(COLOR_PAIR(5));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
printw("\n");
|
||||
printw ("| TID: [%8i] RID: [%8i]", tg, rd);
|
||||
if(state->dmr_so & 0x80) //1000 0000 //prints emergency on some amateru DMR repeaters with 0x8E SOP code, need to investigate
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw (" **Emergency** ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
|
||||
if(state->dmr_so & 0x40) //0100 0000
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw (" **ENC** ");
|
||||
//printw ("0x%X", state->payload_algid);
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
//if (state->K = 0)
|
||||
//{
|
||||
//opts->p25enc = 1; //just testing for now
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
if(state->dmr_so & 0x30) //0010 0000
|
||||
{
|
||||
attron(COLOR_PAIR(2));
|
||||
printw (" **Private Call** ");
|
||||
attroff(COLOR_PAIR(2));
|
||||
attron(COLOR_PAIR(3));
|
||||
}
|
||||
printw("\n");
|
||||
//printw ("%s ", state->slot0light);
|
||||
printw ("| SLOT 0 ");
|
||||
printw ("| SLOT 1 ");
|
||||
if (state->currentslot == 0) //find out how to tell when slot0 has voice
|
||||
{
|
||||
s0last = "Voice";
|
||||
@@ -369,7 +496,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
printw ("%s ", s0last);
|
||||
|
||||
//printw ("%s ", state->slot1light);
|
||||
printw ("SLOT 1 ");
|
||||
printw ("SLOT 2 ");
|
||||
if (state->currentslot == 1) //find out how to tell when slot1 has voice
|
||||
{
|
||||
s1last = "Voice";
|
||||
@@ -380,11 +507,41 @@ 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: [%2i] FID: [%02X] SOP: [%02X] \n", dcc, state->dmr_fid, state->dmr_so);
|
||||
printw ("| TID: [%8i] RID: [%8i]", 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 ");
|
||||
printw ("| SLOT 1 ");
|
||||
if (state->currentslot == 0) //find out how to tell when slot0 has voice
|
||||
{
|
||||
s0last = "Data ";
|
||||
@@ -395,7 +552,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
printw ("%s ", s0last);
|
||||
//printw ("%s ", state->slot1light);
|
||||
printw ("SLOT 1 ");
|
||||
printw ("SLOT 2 ");
|
||||
if (state->currentslot == 1) //find out how to tell when slot1 has voice
|
||||
{
|
||||
s1last = "Data ";
|
||||
@@ -406,6 +563,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]);
|
||||
@@ -434,21 +599,30 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (lls == 8 || lls == 9 || lls == 16 || lls == 17)
|
||||
{
|
||||
printw ("RAN [%2d] ", call_matrix[9-j][1]);
|
||||
printw ("TG [%4d] ", call_matrix[9-j][4]);
|
||||
printw ("RID [%4d] ", call_matrix[9-j][2]);
|
||||
}
|
||||
if (lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 || lls == 11 ) //P25 P1 and DMR
|
||||
{
|
||||
printw ("TID [%2d] ", call_matrix[9-j][1]);
|
||||
printw ("TID [%8d] ", call_matrix[9-j][1]);
|
||||
printw ("RID [%8d] ", call_matrix[9-j][2]);
|
||||
}
|
||||
if (lls == 20 || lls == 21 || lls == 22 || lls == 23 ||lls == 24 || lls == 25 || lls == 26 || lls == 27) //dPMR
|
||||
{
|
||||
printw ("TID [%8d] ", call_matrix[9-j][1]);
|
||||
printw ("RID [%8d] ", call_matrix[9-j][2]);
|
||||
printw ("DCC [%2d] ", call_matrix[9-j][4]);
|
||||
}
|
||||
|
||||
printw ("RID [%4d] ", call_matrix[9-j][2]);
|
||||
//printw ("RID [%08d] ", call_matrix[9-j][2]);
|
||||
//printw ("S %d - ", call_matrix[j][3]);
|
||||
if (call_matrix[9-j][0] == 0 || call_matrix[9-j][0] == 1) //P25P1 Voice
|
||||
{
|
||||
printw ("NAC [0x%X] ", call_matrix[9-j][4]);
|
||||
printw ("NAC [0x%3X] ", call_matrix[9-j][4]);
|
||||
}
|
||||
if (call_matrix[9-j][0] == 12 || call_matrix[9-j][0] == 13 || call_matrix[9-j][0] == 10 || call_matrix[9-j][0] == 11 ) //DMR Voice Types
|
||||
{
|
||||
printw ("DCC [%d] ", call_matrix[9-j][4]);
|
||||
printw ("DCC [%2d] ", call_matrix[9-j][4]);
|
||||
}
|
||||
printw ("%d secs ago\n", time(NULL) - call_matrix[9-j][5]);
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
#ifdef USE_RTLSDR
|
||||
// TODO: need to read demodulated stream here
|
||||
get_rtlsdr_sample(&sample);
|
||||
//state->pulse_raw_out_buffer = sample;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ void dstar_header_decode(int radioheaderbuffer[660]) {
|
||||
radioheader[28], radioheader[29], radioheader[30], radioheader[31],
|
||||
radioheader[32], radioheader[33], radioheader[34], radioheader[35],
|
||||
radioheader[36], radioheader[37], radioheader[38]);
|
||||
|
||||
//FCSinheader = ((radioheader[39] << 8) | radioheader[40]) & 0xFFFF;
|
||||
//FCScalculated = calc_fcs((unsigned char*) radioheader, 39);
|
||||
//fprintf (stderr, "Check sum = %04X ", FCSinheader);
|
||||
|
||||
@@ -574,6 +574,14 @@ void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state,
|
||||
/* Decode the right "Message Type" */
|
||||
switch(MessageType)
|
||||
{
|
||||
//Idle
|
||||
case NXDN_IDLE:
|
||||
{
|
||||
//fprintf(stderr, "NXDN IDLE\n");
|
||||
sprintf (state->nxdn_call_type, "NXDN IDLE ");
|
||||
}
|
||||
break;
|
||||
|
||||
/* VCALL */
|
||||
case NXDN_VCALL:
|
||||
{
|
||||
@@ -726,27 +734,43 @@ void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message)
|
||||
}
|
||||
|
||||
/* Print the "Call Type" */
|
||||
//fprintf(stderr, "%s - ", NXDN_Call_Type_To_Str(CallType));
|
||||
fprintf(stderr, "\n\t %s - ", NXDN_Call_Type_To_Str(CallType)); //line break 1 tab, 2 spaces start this string
|
||||
fprintf(stderr, "\n %s - ", NXDN_Call_Type_To_Str(CallType)); //line break and 1 space
|
||||
//sprintf (state->nxdn_call_type, NXDN_Call_Type_To_Str(CallType)); //fix warning below
|
||||
//warning: format not a string literal and no format arguments [-Wformat-security]
|
||||
sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType)); //fix warning below
|
||||
|
||||
/* Print the "Voice Call Option" */
|
||||
NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode);
|
||||
fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode);
|
||||
|
||||
//state->nxdn_key = (KeyID & 0xFF);
|
||||
//state->nxdn_cipher_type = CipherType;
|
||||
/* Print the "Cipher Type" */
|
||||
if(CipherType != 0) fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType));
|
||||
if(CipherType != 0)
|
||||
{
|
||||
fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType));
|
||||
//state->nxdn_cipher_type = CipherType;
|
||||
}
|
||||
|
||||
/* Print the Key ID */
|
||||
if(CipherType != 0) fprintf(stderr, "Key ID %u - ", KeyID & 0xFF);
|
||||
if(CipherType != 0)
|
||||
{
|
||||
fprintf(stderr, "Key ID %u - ", KeyID & 0xFF);
|
||||
//state->nxdn_key = (KeyID & 0xFF);
|
||||
}
|
||||
|
||||
/* Print Source ID and Destination ID (Talk Group or Unit ID) */
|
||||
fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF);
|
||||
|
||||
|
||||
if(state->NxdnElementsContent.VCallCrcIsGood)
|
||||
{
|
||||
if ( (SourceUnitID & 0xFFFF) > 0 )
|
||||
{
|
||||
state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay
|
||||
state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay
|
||||
state->nxdn_last_tg = (DestinationID & 0xFFFF);
|
||||
state->nxdn_key = (KeyID & 0xFF);
|
||||
state->nxdn_cipher_type = CipherType;
|
||||
}
|
||||
fprintf(stderr, " (OK) - ");
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
char hex[6];
|
||||
int status_count;
|
||||
int status;
|
||||
|
||||
unsigned long long int mihex1, mihex2, mihex3;
|
||||
char hex_data[20][6]; // Data in hex-words (6 bit words). A total of 20 hex words.
|
||||
char hex_parity[16][6]; // Parity of the data, again in hex-word format. A total of 16 parity hex words.
|
||||
|
||||
@@ -461,14 +461,17 @@ processHDU(dsd_opts* opts, dsd_state* state)
|
||||
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
}
|
||||
|
||||
//if (opts->payload == 1)
|
||||
if (opts->payload == 1 && state->errs == 0)
|
||||
//if (state->errs == 0 && algidhex != 0x80)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
//fprintf (stderr, "ALG ID: 0x%X KEY ID: 0x%X\n", algidhex, kidhex);
|
||||
fprintf (stderr, "HDU ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi);
|
||||
//fprintf (stderr, "ALG ID: 0x%X KEY ID: 0x%X MI: 0x%016X%02X\n", algidhex, kidhex, mihex1, mihex2);
|
||||
//fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi);
|
||||
fprintf (stderr, " HDU ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
}
|
||||
|
||||
if (opts->p25enc == 1 && opts->payload == 0)
|
||||
|
||||
194
src/p25p1_ldu2.c
194
src/p25p1_ldu2.c
@@ -22,8 +22,6 @@
|
||||
#include "p25p1_check_ldu.h"
|
||||
#include "p25p1_hdu.h"
|
||||
|
||||
long long int mihex1 = 0;
|
||||
long long int mihex2 = 0;
|
||||
|
||||
void
|
||||
processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
@@ -33,7 +31,7 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
char mi[73], algid[9], kid[17];
|
||||
char lsd1[9], lsd2[9];
|
||||
int algidhex, kidhex;
|
||||
|
||||
unsigned long long int mihex1, mihex2, mihex3;
|
||||
int status_count;
|
||||
|
||||
char hex_data[16][6]; // Data in hex-words (6 bit words). A total of 16 hex words.
|
||||
@@ -249,165 +247,6 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
lsd1[8] = 0;
|
||||
lsd2[8] = 0;
|
||||
|
||||
mihex1 = 0;
|
||||
mihex2 = 0;
|
||||
/*
|
||||
mihex1 |= atoi(&hex_data[15][0]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[15][1]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[15][2]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[15][3]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[15][4]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[15][5]);
|
||||
mihex1 << 1;
|
||||
//fprintf(stderr, "\n%X\n", mihex1);
|
||||
mihex1 |= atoi(&hex_data[14][0]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[14][1]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[14][2]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[14][3]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[14][4]);
|
||||
mihex1 << 1;
|
||||
mihex1 |= atoi(&hex_data[14][5]);
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[13][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[13][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[13][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[13][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[13][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[13][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[12][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[12][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[12][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[12][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[12][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[12][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[113][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[11][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[11][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[11][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[11][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[11][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[10][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[10][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[10][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[10][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[10][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[10][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[9][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[9][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[9][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[9][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[9][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[9][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[8][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[8][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[8][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[8][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[8][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[8][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[7][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[7][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[7][2];
|
||||
mihex1 << 1;
|
||||
mihex1 = hex_data[7][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[7][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[7][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[6][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[6][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[6][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[6][3];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[6][4];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[6][5];
|
||||
mihex1 << 1;
|
||||
|
||||
mihex1 |= hex_data[5][0];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[5][1];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[5][2];
|
||||
mihex1 << 1;
|
||||
mihex1 |= hex_data[5][3];
|
||||
//mihex1 << 1;
|
||||
|
||||
mihex2 |= hex_data[5][4];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[5][5];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][0];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][1];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][2];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][3];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][4];
|
||||
mihex2 << 1;
|
||||
mihex2 |= hex_data[4][5];
|
||||
//mihex2 << 1;
|
||||
*/
|
||||
mi[ 0] = hex_data[15][0] + '0';
|
||||
mi[ 1] = hex_data[15][1] + '0';
|
||||
mi[ 2] = hex_data[15][2] + '0';
|
||||
@@ -520,40 +359,27 @@ processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
kid[14] = hex_data[ 0][4] + '0';
|
||||
kid[15] = hex_data[ 0][5] + '0';
|
||||
|
||||
//if (state->carrier == 1 && state->errs2 == 0) //only update when carrier is present, and no errors??
|
||||
|
||||
if (state->carrier == 1 && state->errs == 0) //only update when carrier is present, and no errors??
|
||||
//if (state->carrier == 1)
|
||||
{
|
||||
/*
|
||||
for (short i = 0; i < 64; i++)
|
||||
{
|
||||
mihex1 << 1;
|
||||
//mihex1 |= strtoll(&mi[i], NULL, 2);
|
||||
mihex1 |= atoi(&mi[i]);
|
||||
//fprintf (stderr, "%c", mi[i]);
|
||||
}
|
||||
for (short i = 0; i < 8; i++)
|
||||
{
|
||||
mihex2 << 1;
|
||||
//mihex2 |= strtoll(&mi[64+i], NULL, 2);
|
||||
mihex2 |= atoi(&mi[i+64]);
|
||||
//fprintf (stderr, "%c", mi[i+64]);
|
||||
}
|
||||
*/
|
||||
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
|
||||
state->payload_algid = algidhex;
|
||||
state->payload_keyid = kidhex;
|
||||
|
||||
mihex1 = (unsigned long long int)ConvertBitIntoBytes(&mi[0], 32);
|
||||
mihex2 = (unsigned long long int)ConvertBitIntoBytes(&mi[32], 32);
|
||||
mihex3 = (unsigned long long int)ConvertBitIntoBytes(&mi[64], 8);
|
||||
}
|
||||
|
||||
//if (opts->payload == 1)
|
||||
if (opts->payload == 1 && state->errs == 0)
|
||||
//if (state->errs == 0 && algidhex != 0x80)
|
||||
if (opts->payload == 1)
|
||||
{
|
||||
//fprintf (stderr, "ALG ID: 0x%X KEY ID: 0x%X\n", algidhex, kidhex);
|
||||
fprintf (stderr, "LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi);
|
||||
//fprintf (stderr, "ALG ID: 0x%X KEY ID: 0x%X MI: 0x%016X%02X\n", algidhex, kidhex, mihex1, mihex2);
|
||||
//fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: %s \n", algidhex, kidhex, mi);
|
||||
fprintf (stderr, " LDU2 ALG ID: 0x%X KEY ID: 0x%X MI: 0x%08llX%08llX%02llX\n", algidhex, kidhex, mihex1, mihex2, mihex3);
|
||||
}
|
||||
//if (opts->p25enc == 1 && opts->payload == 0)
|
||||
if (opts->payload == 0)
|
||||
|
||||
316
src/rs-12-9.c
Normal file
316
src/rs-12-9.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* This file is part of dmrshark.
|
||||
*
|
||||
* dmrshark is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* dmrshark is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with dmrshark. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
// Reed-Solomon (12,9) error-correction coding.
|
||||
//
|
||||
// As there are 3 checksum bytes, we can only correct 1 erroneous byte.
|
||||
//
|
||||
// Based on the code by Henry Minsky (hqm@alum.mit.edu), http://rscode.sourceforge.net
|
||||
// Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location are
|
||||
// from Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205.
|
||||
|
||||
//#include DEFAULTCONFIG
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
//#include <libs/daemon/console.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t error_locations[256];
|
||||
uint8_t errors_num;
|
||||
} rs_12_9_roots_t;
|
||||
|
||||
// See DMR AI. spec. page 138.
|
||||
static uint8_t rs_12_9_galois_exp_table[256] = {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1D, 0x3A, 0x74, 0xE8, 0xCD, 0x87, 0x13, 0x26,
|
||||
0x4C, 0x98, 0x2D, 0x5A, 0xB4, 0x75, 0xEA, 0xC9, 0x8F, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0,
|
||||
0x9D, 0x27, 0x4E, 0x9C, 0x25, 0x4A, 0x94, 0x35, 0x6A, 0xD4, 0xB5, 0x77, 0xEE, 0xC1, 0x9F, 0x23,
|
||||
0x46, 0x8C, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x5D, 0xBA, 0x69, 0xD2, 0xB9, 0x6F, 0xDE, 0xA1,
|
||||
0x5F, 0xBE, 0x61, 0xC2, 0x99, 0x2F, 0x5E, 0xBC, 0x65, 0xCA, 0x89, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
|
||||
0xFD, 0xE7, 0xD3, 0xBB, 0x6B, 0xD6, 0xB1, 0x7F, 0xFE, 0xE1, 0xDF, 0xA3, 0x5B, 0xB6, 0x71, 0xE2,
|
||||
0xD9, 0xAF, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xBD, 0x67, 0xCE,
|
||||
0x81, 0x1F, 0x3E, 0x7C, 0xF8, 0xED, 0xC7, 0x93, 0x3B, 0x76, 0xEC, 0xC5, 0x97, 0x33, 0x66, 0xCC,
|
||||
0x85, 0x17, 0x2E, 0x5C, 0xB8, 0x6D, 0xDA, 0xA9, 0x4F, 0x9E, 0x21, 0x42, 0x84, 0x15, 0x2A, 0x54,
|
||||
0xA8, 0x4D, 0x9A, 0x29, 0x52, 0xA4, 0x55, 0xAA, 0x49, 0x92, 0x39, 0x72, 0xE4, 0xD5, 0xB7, 0x73,
|
||||
0xE6, 0xD1, 0xBF, 0x63, 0xC6, 0x91, 0x3F, 0x7E, 0xFC, 0xE5, 0xD7, 0xB3, 0x7B, 0xF6, 0xF1, 0xFF,
|
||||
0xE3, 0xDB, 0xAB, 0x4B, 0x96, 0x31, 0x62, 0xC4, 0x95, 0x37, 0x6E, 0xDC, 0xA5, 0x57, 0xAE, 0x41,
|
||||
0x82, 0x19, 0x32, 0x64, 0xC8, 0x8D, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xDD, 0xA7, 0x53, 0xA6,
|
||||
0x51, 0xA2, 0x59, 0xB2, 0x79, 0xF2, 0xF9, 0xEF, 0xC3, 0x9B, 0x2B, 0x56, 0xAC, 0x45, 0x8A, 0x09,
|
||||
0x12, 0x24, 0x48, 0x90, 0x3D, 0x7A, 0xF4, 0xF5, 0xF7, 0xF3, 0xFB, 0xEB, 0xCB, 0x8B, 0x0B, 0x16,
|
||||
0x2C, 0x58, 0xB0, 0x7D, 0xFA, 0xE9, 0xCF, 0x83, 0x1B, 0x36, 0x6C, 0xD8, 0xAD, 0x47, 0x8E, 0x01,
|
||||
};
|
||||
|
||||
// See DMR AI. spec. page 138.
|
||||
static uint8_t rs_12_9_galois_log_table[256] = {
|
||||
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75,
|
||||
4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
|
||||
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69,
|
||||
29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166,
|
||||
6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
|
||||
54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64,
|
||||
30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
|
||||
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87,
|
||||
7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
|
||||
227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
|
||||
55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97,
|
||||
242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162,
|
||||
31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246,
|
||||
108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90,
|
||||
203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
|
||||
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
|
||||
};
|
||||
|
||||
static uint8_t rs_12_9_galois_exp_table_get(uint8_t pos) {
|
||||
return rs_12_9_galois_exp_table[pos];
|
||||
}
|
||||
|
||||
static uint8_t rs_12_9_galois_multiplication(uint8_t a, uint8_t b) {
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
|
||||
return rs_12_9_galois_exp_table[(rs_12_9_galois_log_table[a] + rs_12_9_galois_log_table[b]) % 255];
|
||||
}
|
||||
|
||||
static uint8_t rs_12_9_galois_inv(uint8_t elt) {
|
||||
return rs_12_9_galois_exp_table[255-rs_12_9_galois_log_table[elt]];
|
||||
}
|
||||
|
||||
// Multiply by z (shift right by 1).
|
||||
static void rs_12_9_multiply_poly_z(rs_12_9_poly_t *poly) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = RS_12_9_POLY_MAXDEG-1; i > 0; i--)
|
||||
poly->data[i] = poly->data[i-1];
|
||||
poly->data[0] = 0;
|
||||
}
|
||||
|
||||
static void rs_12_9_multiplicate_polys(uint8_t dst[], rs_12_9_poly_t *p1, rs_12_9_poly_t *p2) {
|
||||
uint8_t i;
|
||||
int8_t j;
|
||||
int8_t tmp1[RS_12_9_POLY_MAXDEG*2];
|
||||
|
||||
for (i = 0; i < RS_12_9_POLY_MAXDEG*2; i++)
|
||||
dst[i] = 0;
|
||||
|
||||
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++) {
|
||||
for(j = RS_12_9_POLY_MAXDEG; j < (RS_12_9_POLY_MAXDEG*2); j++)
|
||||
tmp1[j] = 0;
|
||||
|
||||
// Scale tmp1 by p1[i]
|
||||
for(j = 0; j < RS_12_9_POLY_MAXDEG; j++)
|
||||
tmp1[j] = rs_12_9_galois_multiplication(p2->data[j], p1->data[i]);
|
||||
|
||||
// Shift (multiply) tmp1 right by i
|
||||
for (j = (RS_12_9_POLY_MAXDEG*2)-1; j >= i; j--)
|
||||
tmp1[j] = tmp1[j-i];
|
||||
for (j = 0; j < i; j++)
|
||||
tmp1[j] = 0;
|
||||
|
||||
// Add into partial product.
|
||||
for (j = 0; j < (RS_12_9_POLY_MAXDEG*2); j++)
|
||||
dst[j] ^= tmp1[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the combined erasure/error evaluator polynomial (error_locator_poly*syndrome mod z^4)
|
||||
static void rs_12_9_calc_error_evaluator_poly(rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *syndrome, rs_12_9_poly_t *error_evaluator_poly) {
|
||||
uint8_t i;
|
||||
uint8_t product[RS_12_9_POLY_MAXDEG*2];
|
||||
|
||||
rs_12_9_multiplicate_polys(product, error_locator_poly, syndrome);
|
||||
for (i = 0; i < RS_12_9_CHECKSUMSIZE; i++)
|
||||
error_evaluator_poly->data[i] = product[i];
|
||||
for (; i < RS_12_9_POLY_MAXDEG; i++)
|
||||
error_evaluator_poly->data[i] = 0;
|
||||
}
|
||||
|
||||
static uint8_t rs_12_9_compute_discrepancy(rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *syndrome, uint8_t L, uint8_t n) {
|
||||
uint8_t i;
|
||||
uint8_t sum = 0;
|
||||
|
||||
for (i = 0; i <= L; i++)
|
||||
sum ^= rs_12_9_galois_multiplication(error_locator_poly->data[i], syndrome->data[n-i]);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// This finds the coefficients of the error locator polynomial, and then calculates
|
||||
// the error evaluator polynomial using the Berlekamp-Massey algorithm.
|
||||
// From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216.
|
||||
static void rs_12_9_calculate(rs_12_9_poly_t *syndrome, rs_12_9_poly_t *error_locator_poly, rs_12_9_poly_t *error_evaluator_poly) {
|
||||
uint8_t n;
|
||||
uint8_t L = 0;
|
||||
uint8_t L2;
|
||||
int8_t k;
|
||||
uint8_t d;
|
||||
uint8_t i;
|
||||
uint8_t psi2[RS_12_9_POLY_MAXDEG];
|
||||
rs_12_9_poly_t D = { .data = { 0, 1, 0, } };
|
||||
|
||||
k = -1;
|
||||
memset(error_locator_poly, 0, sizeof(rs_12_9_poly_t));
|
||||
error_locator_poly->data[0] = 1;
|
||||
|
||||
for (n = 0; n < RS_12_9_CHECKSUMSIZE; n++) {
|
||||
d = rs_12_9_compute_discrepancy(error_locator_poly, syndrome, L, n);
|
||||
|
||||
if (d != 0) {
|
||||
// psi2 = error_locator_poly - d*D
|
||||
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
|
||||
psi2[i] = error_locator_poly->data[i] ^ rs_12_9_galois_multiplication(d, D.data[i]);
|
||||
|
||||
if (L < (n-k)) {
|
||||
L2 = n-k;
|
||||
k = n-L;
|
||||
|
||||
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
|
||||
D.data[i] = rs_12_9_galois_multiplication(error_locator_poly->data[i], rs_12_9_galois_inv(d));
|
||||
|
||||
L = L2;
|
||||
}
|
||||
|
||||
// error_locator_poly = psi2
|
||||
for (i = 0; i < RS_12_9_POLY_MAXDEG; i++)
|
||||
error_locator_poly->data[i] = psi2[i];
|
||||
}
|
||||
|
||||
rs_12_9_multiply_poly_z(&D);
|
||||
}
|
||||
|
||||
rs_12_9_calc_error_evaluator_poly(error_locator_poly, syndrome, error_evaluator_poly);
|
||||
}
|
||||
|
||||
// The error-locator polynomial's roots are found by looking for the values of a^n where
|
||||
// evaluating the polynomial yields zero (evaluating rs_12_9_error_locator_poly at
|
||||
// successive values of alpha (Chien's search)).
|
||||
static rs_12_9_roots_t *rs_12_9_find_roots(rs_12_9_poly_t *error_locator_poly) {
|
||||
static rs_12_9_roots_t roots;
|
||||
uint8_t sum;
|
||||
uint16_t r;
|
||||
uint8_t k;
|
||||
|
||||
memset(&roots, 0, sizeof(rs_12_9_roots_t));
|
||||
|
||||
for (r = 1; r < 256; r++) {
|
||||
sum = 0;
|
||||
// Evaluate rs_12_9_error_locator_poly at r
|
||||
for (k = 0; k < RS_12_9_CHECKSUMSIZE+1; k++)
|
||||
sum ^= rs_12_9_galois_multiplication(rs_12_9_galois_exp_table_get((k*r) % 255), error_locator_poly->data[k]);
|
||||
|
||||
if (sum == 0)
|
||||
roots.error_locations[roots.errors_num++] = (255-r);
|
||||
}
|
||||
return &roots;
|
||||
}
|
||||
|
||||
void rs_12_9_calc_syndrome(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome) {
|
||||
uint8_t i, j;
|
||||
|
||||
syndrome->data[0] = syndrome->data[1] = syndrome->data[2] = 0;
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
for (i = 0; i < sizeof(rs_12_9_codeword_t); i++)
|
||||
syndrome->data[j] = codeword->data[i] ^ rs_12_9_galois_multiplication(rs_12_9_galois_exp_table_get(j+1), syndrome->data[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns 1 if syndrome differs from all zeroes.
|
||||
uint8_t rs_12_9_check_syndrome(rs_12_9_poly_t *syndrome) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (syndrome->data[i] != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// Returns 1 if errors have been found and corrected, returns 0 if
|
||||
// no errors found or errors can't be corrected.
|
||||
rs_12_9_correct_errors_result_t rs_12_9_correct_errors(rs_12_9_codeword_t *codeword, rs_12_9_poly_t *syndrome, uint8_t *errors_found) {
|
||||
uint8_t r;
|
||||
uint8_t i;
|
||||
uint8_t j;
|
||||
uint8_t err;
|
||||
rs_12_9_poly_t error_locator_poly;
|
||||
rs_12_9_poly_t error_evaluator_poly;
|
||||
rs_12_9_roots_t *roots;
|
||||
uint8_t num, denom;
|
||||
|
||||
rs_12_9_calculate(syndrome, &error_locator_poly, &error_evaluator_poly);
|
||||
roots = rs_12_9_find_roots(&error_locator_poly);
|
||||
*errors_found = roots->errors_num;
|
||||
|
||||
if (roots->errors_num == 0)
|
||||
return RS_12_9_CORRECT_ERRORS_RESULT_NO_ERRORS_FOUND;
|
||||
|
||||
// Error correction is done using the error-evaluator equation on pp 207.
|
||||
if (roots->errors_num > 0 && roots->errors_num <= RS_12_9_CHECKSUMSIZE) {
|
||||
// First check for illegal error locations.
|
||||
for (r = 0; r < roots->errors_num; r++) {
|
||||
if (roots->error_locations[r] >= RS_12_9_DATASIZE+RS_12_9_CHECKSUMSIZE)
|
||||
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CANT_BE_CORRECTED;
|
||||
}
|
||||
|
||||
// Evaluates rs_12_9_error_evaluator_poly/rs_12_9_error_locator_poly' at the roots
|
||||
// alpha^(-i) for error locs i.
|
||||
for (r = 0; r < roots->errors_num; r++) {
|
||||
i = roots->error_locations[r];
|
||||
|
||||
// Evaluate rs_12_9_error_evaluator_poly at alpha^(-i)
|
||||
num = 0;
|
||||
for (j = 0; j < RS_12_9_POLY_MAXDEG; j++)
|
||||
num ^= rs_12_9_galois_multiplication(error_evaluator_poly.data[j], rs_12_9_galois_exp_table_get(((255-i)*j) % 255));
|
||||
|
||||
// Evaluate rs_12_9_error_evaluator_poly' (derivative) at alpha^(-i). All odd powers disappear.
|
||||
denom = 0;
|
||||
for (j = 1; j < RS_12_9_POLY_MAXDEG; j += 2)
|
||||
denom ^= rs_12_9_galois_multiplication(error_locator_poly.data[j], rs_12_9_galois_exp_table_get(((255-i)*(j-1)) % 255));
|
||||
|
||||
err = rs_12_9_galois_multiplication(num, rs_12_9_galois_inv(denom));
|
||||
//console_log(LOGLEVEL_CODING LOGLEVEL_DEBUG " rs (12,9): error magnitude %#x at byte loc. %u\n", err, sizeof(rs_12_9_codeword_t)-i);
|
||||
|
||||
codeword->data[sizeof(rs_12_9_codeword_t)-i-1] ^= err;
|
||||
}
|
||||
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CORRECTED;
|
||||
}
|
||||
|
||||
return RS_12_9_CORRECT_ERRORS_RESULT_ERRORS_CANT_BE_CORRECTED;
|
||||
}
|
||||
|
||||
// Simulates an LFSR with the generator polynomial and calculates checksum bytes for the given data.
|
||||
rs_12_9_checksum_t *rs_12_9_calc_checksum(rs_12_9_codeword_t *codeword) {
|
||||
// See DMR AI. spec. page 136 for these coefficients.
|
||||
static uint8_t genpoly[] = { 0x40, 0x38, 0x0e, 0x01 };
|
||||
static rs_12_9_checksum_t rs_12_9_checksum;
|
||||
uint8_t i;
|
||||
uint8_t feedback;
|
||||
|
||||
rs_12_9_checksum.bytes[0] = rs_12_9_checksum.bytes[1] = rs_12_9_checksum.bytes[2] = 0;
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
feedback = codeword->data[i] ^ rs_12_9_checksum.bytes[0];
|
||||
|
||||
rs_12_9_checksum.bytes[0] = rs_12_9_checksum.bytes[1] ^ rs_12_9_galois_multiplication(genpoly[2], feedback);
|
||||
rs_12_9_checksum.bytes[1] = rs_12_9_checksum.bytes[2] ^ rs_12_9_galois_multiplication(genpoly[1], feedback);
|
||||
rs_12_9_checksum.bytes[2] = rs_12_9_galois_multiplication(genpoly[0], feedback);
|
||||
}
|
||||
return &rs_12_9_checksum;
|
||||
}
|
||||
Reference in New Issue
Block a user