dsd-fme_20_06_2023/src/dpmr_voice.c

705 lines
21 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"
#include "dpmr_const.h"
void processdPMRvoice (dsd_opts * opts, dsd_state * state)
{
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];
uint8_t CCHDataCRC[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
memset (CCHDataHammingCorrected, 1, sizeof(CCHDataHammingCorrected));
memset (CCHDataCRC, 1, sizeof(CCHDataCRC));
uint8_t CCHDataCRCComputed[NB_OF_DPMR_VOICE_FRAME_TO_DECODE];
memset (CCHDataCRCComputed, 0, sizeof(CCHDataCRCComputed));
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];
memset (ambe_fr, 0, sizeof (ambe_fr));
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};
/* 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
}
/* 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);
}
ambe_fr[j][*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[j][*y][*z] = (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++;
}
}
/* 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
}
/* 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
}
/* 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);
}
ambe_fr[j + 4][*w][*x] = (1 & (dibit >> 1)); // bit 1
ambe_fr[j + 4][*y][*z] = (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++;
}
}
/* 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) HammingOk[i] = 1;
else 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]) CrcOk[i] = 1;
else 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';
/* 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;
/* 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;
/* 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)
{
/* Set the next part as the second part */
opts->dPMR_next_part_of_superframe = 2;
}
else if(opts->dPMR_next_part_of_superframe == 2)
{
/* Set the next part as the first part */
opts->dPMR_next_part_of_superframe = 1;
}
else
{
/* Unknown current part, set to 0 */
opts->dPMR_next_part_of_superframe = 0;
}
}
/* Display the destination ID (talk group - TG) */
fprintf (stderr, "\n");
if(state->dPMRVoiceFS2Frame.CalledIDOk)
{
fprintf (stderr, "%s", KGRN);
fprintf(stderr, " TG=%s", CalledID);
fprintf (stderr, "%s", KNRM);
//check other as well before assigning
if(state->dPMRVoiceFS2Frame.CallingIDOk) sprintf (state->dpmr_target_id, "%s", CalledID);
}
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " TG=(CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
/* Display the source ID */
if(state->dPMRVoiceFS2Frame.CallingIDOk)
{
fprintf (stderr, "%s", KGRN);
fprintf(stderr, " Src=%s", CallingID);
fprintf (stderr, "%s", KNRM);
//check other as well before assigning
if(state->dPMRVoiceFS2Frame.CalledIDOk) sprintf (state->dpmr_caller_id, "%s", CallingID);
//stashed channel code in here, more likely to be correct, but no guarantee
if(state->dPMRVoiceFS2Frame.ColorCode[0] != (unsigned int)(-1))
{
fprintf (stderr, "%s", KGRN);
fprintf(stderr, " Channel Code=%02d", (int)state->dPMRVoiceFS2Frame.ColorCode[0]);
fprintf (stderr, "%s", KNRM);
//check other as well before assigning
if(state->dPMRVoiceFS2Frame.CalledIDOk) state->dpmr_color_code = (int)state->dPMRVoiceFS2Frame.ColorCode[0];
}
}
else
{
fprintf (stderr, "%s", KRED);
fprintf(stderr, " Src=(CRC ERR) Channel Code =(CRC ERR)");
fprintf (stderr, "%s", KNRM);
}
if (state->dPMRVoiceFS2Frame.Version[0] == 3)
{
fprintf (stderr, "%s", KRED);
fprintf (stderr, " Scrambler");
fprintf (stderr, "%s", KNRM);
if (state->R != 0)
{
fprintf (stderr, "%s", KYEL);
fprintf (stderr, " Key %05lld ", state->R );
fprintf (stderr, "%s", KNRM);
}
}
//Play only voice frames by first looking to see if there is a TCH voice in CommunicationMode,
short start = 0;
short end = 4;
//not really even sure why I made this loop
//I probably should actually read the manual again
for (short o = 0; o < 2; o++)
{
//reset scrambler key seed on frame 0
if (state->dPMRVoiceFS2Frame.FrameNumbering[o] == 0) state->payload_miN = 0;
//depending on first or second TCH, set start and end variables appropriately
if (o == 1)
{
start = 4;
end = 8;
}
//this is used so we can simply pass the voice here to the
//nxdn scrambler by telling mbe these are nxdn frames and to
//apply the same descramble method to them if necessary
int realsynctype = state->synctype;
// fprintf (stderr, "\nCommunication Mode: %d\n", state->dPMRVoiceFS2Frame.CommunicationMode[o]);
// fprintf (stderr, "Encryption Mode: %d\n", state->dPMRVoiceFS2Frame.Version[o]); //shows as 3 (manufacturer specific, 5.16) on the dPMR scrambler values received
// fprintf (stderr, "Superframe Number: %d", state->dPMRVoiceFS2Frame.FrameNumbering[o]);
if((state->dPMRVoiceFS2Frame.CommunicationMode[o] == 0) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 1) ||
(state->dPMRVoiceFS2Frame.CommunicationMode[o] == 5))
{
//check to see if we are using scrambler
if (state->dPMRVoiceFS2Frame.Version[o] == 3) //!= 0
{
state->synctype = 28; //fake it as nxdn
state->nxdn_cipher_type = 0x01; //turn on nxdn scrambler cipher
state->dmr_encL = 1; //flag on enc bit here so we can mute if no key provided
}
//flag back off if key is provided
if (state->R != 0) state->dmr_encL = 0;
//There are 4 AMBE voice frames per TCH
for(i = start; i < end; i++)
{
processMbeFrame (opts, state, NULL, ambe_fr[i], NULL);
}
//set the correct sync type again and flag off the cipher
state->synctype = realsynctype;
state->nxdn_cipher_type = 0;
}
}
fprintf(stderr, "\n");
//keep code below, could be handy cheat sheet for other info
#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
} //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 descramble 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 scrambling / descrambling,
* see ETSI TS 102 658 chapter 7.4 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 */