Files
dsd-fme/src/dmr_sync.c
lwvmobile 184b8b6a39 Enable D-Star, Pulse Tweaks, NCurses Tweaks, Misc
Enable D-Star, Pulse Tweaks, NCurses Tweaks, Misc
2022-03-13 19:13:09 -04:00

939 lines
30 KiB
C

/*
* 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 */