/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance * contact@openairinterface.org */ /*!\file PHY/CODING/nrPolar_tools/nr_polar_decoder.c * \brief * \author Raymond Knopp, Turker Yilmaz * \date 2018 * \version 0.1 * \company EURECOM * \email raymond.knopp@eurecom.fr, turker.yilmaz@eurecom.fr * \note * \warning */ /* * Return values: * 0 --> Success * -1 --> All list entries have failed the CRC checks */ #include "PHY/CODING/nrPolar_tools/nr_polar_defs.h" #include "assertions.h" int8_t polar_decoder(double *input, uint32_t *out, t_nrPolar_params *polarParams, uint8_t listSize) { //Assumes no a priori knowledge. uint8_t ***bit = nr_alloc_uint8_3D_array(polarParams->N, (polarParams->n+1), 2*listSize); uint8_t **bitUpdated = nr_alloc_uint8_2D_array(polarParams->N, (polarParams->n+1)); //0=False, 1=True uint8_t **llrUpdated = nr_alloc_uint8_2D_array(polarParams->N, (polarParams->n+1)); //0=False, 1=True double ***llr = nr_alloc_double_3D_array(polarParams->N, (polarParams->n+1), 2*listSize); uint8_t **crcChecksum = nr_alloc_uint8_2D_array(polarParams->crcParityBits, 2*listSize); double *pathMetric = malloc(sizeof(double)*(2*listSize)); uint8_t *crcState = malloc(sizeof(uint8_t)*(2*listSize)); //0=False, 1=True for (int i=0; i<(2*listSize); i++) { pathMetric[i] = 0; crcState[i]=1; } for (int i=0; i<polarParams->N; i++) { llrUpdated[i][polarParams->n]=1; bitUpdated[i][0]=((polarParams->information_bit_pattern[i]+1) % 2); } uint8_t **extended_crc_generator_matrix = malloc(polarParams->K * sizeof(uint8_t *)); //G_P3 uint8_t **tempECGM = malloc(polarParams->K * sizeof(uint8_t *)); //G_P2 for (int i = 0; i < polarParams->K; i++) { extended_crc_generator_matrix[i] = malloc(polarParams->crcParityBits * sizeof(uint8_t)); tempECGM[i] = malloc(polarParams->crcParityBits * sizeof(uint8_t)); } for (int i=0; i<polarParams->payloadBits; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { tempECGM[i][j]=polarParams->crc_generator_matrix[i][j]; } } for (int i=polarParams->payloadBits; i<polarParams->K; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { if( (i-polarParams->payloadBits) == j ) { tempECGM[i][j]=1; } else { tempECGM[i][j]=0; } } } for (int i=0; i<polarParams->K; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { extended_crc_generator_matrix[i][j]=tempECGM[polarParams->interleaving_pattern[i]][j]; } } //The index of the last 1-valued bit that appears in each column. uint16_t last1ind[polarParams->crcParityBits]; for (int j=0; j<polarParams->crcParityBits; j++) { for (int i=0; i<polarParams->K; i++) { if (extended_crc_generator_matrix[i][j]==1) last1ind[j]=i; } } double *d_tilde = malloc(sizeof(double) * polarParams->N); nr_polar_rate_matching(input, d_tilde, polarParams->rate_matching_pattern, polarParams->K, polarParams->N, polarParams->encoderLength); for (int j = 0; j < polarParams->N; j++) llr[j][polarParams->n][0]=d_tilde[j]; /* * SCL polar decoder. */ uint32_t nonFrozenBit=0; uint8_t currentListSize=1; uint8_t decoderIterationCheck=0; int16_t checkCrcBits=-1; uint8_t listIndex[2*listSize], copyIndex; for (uint16_t currentBit=0; currentBit<polarParams->N; currentBit++) { updateLLR(llr, llrUpdated, bit, bitUpdated, currentListSize, currentBit, 0, polarParams->N, (polarParams->n+1)); if (polarParams->information_bit_pattern[currentBit]==0) { //Frozen bit. updatePathMetric(pathMetric, llr, currentListSize, 0, currentBit); } else { //Information or CRC bit. updatePathMetric2(pathMetric, llr, currentListSize, currentBit); for (int i = 0; i < currentListSize; i++) { for (int j = 0; j < polarParams->N; j++) { for (int k = 0; k < (polarParams->n+1); k++) { bit[j][k][i+currentListSize]=bit[j][k][i]; llr[j][k][i+currentListSize]=llr[j][k][i]; } } } for (int i = 0; i < currentListSize; i++) { bit[currentBit][0][i]=0; crcState[i+currentListSize]=crcState[i]; } for (int i = currentListSize; i < 2*currentListSize; i++) bit[currentBit][0][i]=1; bitUpdated[currentBit][0]=1; updateCrcChecksum2(crcChecksum, extended_crc_generator_matrix, currentListSize, nonFrozenBit, polarParams->crcParityBits); currentListSize*=2; //Keep only the best "listSize" number of entries. if (currentListSize > listSize) { for (uint8_t i = 0; i < 2*listSize; i++) listIndex[i]=i; nr_sort_asc_double_1D_array_ind(pathMetric, listIndex, currentListSize); //sort listIndex[listSize, ..., 2*listSize-1] in descending order. uint8_t swaps, tempInd; for (uint8_t i = 0; i < listSize; i++) { swaps = 0; for (uint8_t j = listSize; j < (2*listSize - i) - 1; j++) { if (listIndex[j+1] > listIndex[j]) { tempInd = listIndex[j]; listIndex[j] = listIndex[j + 1]; listIndex[j + 1] = tempInd; swaps++; } } if (swaps == 0) break; } //First, backup the best "listSize" number of entries. for (int k=(listSize-1); k>0; k--) { for (int i=0; i<polarParams->N; i++) { for (int j=0; j<(polarParams->n+1); j++) { bit[i][j][listIndex[(2*listSize-1)-k]]=bit[i][j][listIndex[k]]; llr[i][j][listIndex[(2*listSize-1)-k]]=llr[i][j][listIndex[k]]; } } } for (int k=(listSize-1); k>0; k--) { for (int i = 0; i < polarParams->crcParityBits; i++) { crcChecksum[i][listIndex[(2*listSize-1)-k]] = crcChecksum[i][listIndex[k]]; } } for (int k=(listSize-1); k>0; k--) crcState[listIndex[(2*listSize-1)-k]]=crcState[listIndex[k]]; //Copy the best "listSize" number of entries to the first indices. for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } for (int i = 0; i < polarParams->N; i++) { for (int j = 0; j < (polarParams->n + 1); j++) { bit[i][j][k] = bit[i][j][copyIndex]; llr[i][j][k] = llr[i][j][copyIndex]; } } } for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } for (int i = 0; i < polarParams->crcParityBits; i++) { crcChecksum[i][k]=crcChecksum[i][copyIndex]; } } for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } crcState[k]=crcState[copyIndex]; } currentListSize = listSize; } for (int i=0; i<polarParams->crcParityBits; i++) { if (last1ind[i]==nonFrozenBit) { checkCrcBits=i; break; } } if ( checkCrcBits > (-1) ) { for (uint8_t i = 0; i < currentListSize; i++) { if (crcChecksum[checkCrcBits][i]==1) { crcState[i]=0; //0=False, 1=True } } } for (uint8_t i = 0; i < currentListSize; i++) decoderIterationCheck+=crcState[i]; if (decoderIterationCheck==0) { //perror("[SCL polar decoder] All list entries have failed the CRC checks."); free(d_tilde); free(pathMetric); free(crcState); nr_free_uint8_3D_array(bit, polarParams->N, (polarParams->n+1)); nr_free_double_3D_array(llr, polarParams->N, (polarParams->n+1)); nr_free_uint8_2D_array(crcChecksum, polarParams->crcParityBits); return(-1); } nonFrozenBit++; decoderIterationCheck=0; checkCrcBits=-1; } } for (uint8_t i = 0; i < 2*listSize; i++) listIndex[i]=i; nr_sort_asc_double_1D_array_ind(pathMetric, listIndex, currentListSize); for (uint8_t i = 0; i < fmin(listSize, (pow(2,polarParams->crcCorrectionBits)) ); i++) { if ( crcState[listIndex[i]] == 1 ) { for (int j = 0; j < polarParams->N; j++) polarParams->nr_polar_U[j]=bit[j][0][listIndex[i]]; //Extract the information bits (û to ĉ) nr_polar_info_bit_extraction(polarParams->nr_polar_U, polarParams->nr_polar_CPrime, polarParams->information_bit_pattern, polarParams->N); //Deinterleaving (ĉ to b) nr_polar_deinterleaver(polarParams->nr_polar_CPrime, polarParams->nr_polar_B, polarParams->interleaving_pattern, polarParams->K); //Remove the CRC (â) for (int j = 0; j < polarParams->payloadBits; j++) polarParams->nr_polar_A[j]=polarParams->nr_polar_B[j]; break; } } free(d_tilde); free(pathMetric); free(crcState); nr_free_uint8_3D_array(bit, polarParams->N, (polarParams->n+1)); nr_free_double_3D_array(llr, polarParams->N, (polarParams->n+1)); nr_free_uint8_2D_array(crcChecksum, polarParams->crcParityBits); nr_free_uint8_2D_array(extended_crc_generator_matrix, polarParams->K); nr_free_uint8_2D_array(tempECGM, polarParams->K); /* * Return bits. */ nr_byte2bit_uint8_32(polarParams->nr_polar_A, polarParams->payloadBits, out); return(0); } int8_t polar_decoder_dci(double *input, uint32_t *out, t_nrPolar_params *polarParams, uint8_t listSize, uint16_t n_RNTI) { uint8_t ***bit = nr_alloc_uint8_3D_array(polarParams->N, (polarParams->n+1), 2*listSize); uint8_t **bitUpdated = nr_alloc_uint8_2D_array(polarParams->N, (polarParams->n+1)); //0=False, 1=True uint8_t **llrUpdated = nr_alloc_uint8_2D_array(polarParams->N, (polarParams->n+1)); //0=False, 1=True double ***llr = nr_alloc_double_3D_array(polarParams->N, (polarParams->n+1), 2*listSize); uint8_t **crcChecksum = nr_alloc_uint8_2D_array(polarParams->crcParityBits, 2*listSize); double *pathMetric = malloc(sizeof(double)*(2*listSize)); uint8_t *crcState = malloc(sizeof(uint8_t)*(2*listSize)); //0=False, 1=True uint8_t extended_crc_scrambling_pattern[polarParams->crcParityBits]; for (int i=0; i<(2*listSize); i++) { pathMetric[i] = 0; crcState[i]=1; } for (int i=0; i<polarParams->N; i++) { llrUpdated[i][polarParams->n]=1; bitUpdated[i][0]=((polarParams->information_bit_pattern[i]+1) % 2); } uint8_t **extended_crc_generator_matrix = malloc(polarParams->K * sizeof(uint8_t *)); //G_P3: K-by-P uint8_t **tempECGM = malloc(polarParams->K * sizeof(uint8_t *)); //G_P2: K-by-P for (int i = 0; i < polarParams->K; i++) { extended_crc_generator_matrix[i] = malloc(polarParams->crcParityBits * sizeof(uint8_t)); tempECGM[i] = malloc(polarParams->crcParityBits * sizeof(uint8_t)); } for (int i=0; i<polarParams->payloadBits; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { tempECGM[i][j]=polarParams->crc_generator_matrix[i+polarParams->crcParityBits][j]; } } for (int i=polarParams->payloadBits; i<polarParams->K; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { if( (i-polarParams->payloadBits) == j ) { tempECGM[i][j]=1; } else { tempECGM[i][j]=0; } } } for (int i=0; i<polarParams->K; i++) { for (int j=0; j<polarParams->crcParityBits; j++) { extended_crc_generator_matrix[i][j]=tempECGM[polarParams->interleaving_pattern[i]][j]; } } //The index of the last 1-valued bit that appears in each column. uint16_t last1ind[polarParams->crcParityBits]; for (int j=0; j<polarParams->crcParityBits; j++) { for (int i=0; i<polarParams->K; i++) { if (extended_crc_generator_matrix[i][j]==1) last1ind[j]=i; } } for (int i=0; i<8; i++) extended_crc_scrambling_pattern[i]=0; for (int i=8; i<polarParams->crcParityBits; i++) { extended_crc_scrambling_pattern[i]=(n_RNTI>>(23-i))&1; } double *d_tilde = malloc(sizeof(double) * polarParams->N); nr_polar_rate_matching(input, d_tilde, polarParams->rate_matching_pattern, polarParams->K, polarParams->N, polarParams->encoderLength); for (int j = 0; j < polarParams->N; j++) llr[j][polarParams->n][0]=d_tilde[j]; /* * SCL polar decoder. */ for (int i=0; i<polarParams->crcParityBits; i++) { for (int j=0; j<polarParams->crcParityBits; j++) crcChecksum[i][0]=crcChecksum[i][0]+polarParams->crc_generator_matrix[j][i]; crcChecksum[i][0]=(crcChecksum[i][0]%2); } uint32_t nonFrozenBit=0; uint8_t currentListSize=1; uint8_t decoderIterationCheck=0; int16_t checkCrcBits=-1; uint8_t listIndex[2*listSize], copyIndex; for (uint16_t currentBit=0; currentBit<polarParams->N; currentBit++) { updateLLR(llr, llrUpdated, bit, bitUpdated, currentListSize, currentBit, 0, polarParams->N, (polarParams->n+1)); if (polarParams->information_bit_pattern[currentBit]==0) { //Frozen bit. updatePathMetric(pathMetric, llr, currentListSize, 0, currentBit); } else { //Information or CRC bit. updatePathMetric2(pathMetric, llr, currentListSize, currentBit); for (int i = 0; i < currentListSize; i++) { for (int j = 0; j < polarParams->N; j++) { for (int k = 0; k < (polarParams->n+1); k++) { bit[j][k][i+currentListSize]=bit[j][k][i]; llr[j][k][i+currentListSize]=llr[j][k][i]; } } } for (int i = 0; i < currentListSize; i++) { bit[currentBit][0][i]=0; crcState[i+currentListSize]=crcState[i]; } for (int i = currentListSize; i < 2*currentListSize; i++) bit[currentBit][0][i]=1; bitUpdated[currentBit][0]=1; updateCrcChecksum2(crcChecksum, extended_crc_generator_matrix, currentListSize, nonFrozenBit, polarParams->crcParityBits); currentListSize*=2; //Keep only the best "listSize" number of entries. if (currentListSize > listSize) { for (uint8_t i = 0; i < 2*listSize; i++) listIndex[i]=i; nr_sort_asc_double_1D_array_ind(pathMetric, listIndex, currentListSize); //sort listIndex[listSize, ..., 2*listSize-1] in descending order. uint8_t swaps, tempInd; for (uint8_t i = 0; i < listSize; i++) { swaps = 0; for (uint8_t j = listSize; j < (2*listSize - i) - 1; j++) { if (listIndex[j+1] > listIndex[j]) { tempInd = listIndex[j]; listIndex[j] = listIndex[j + 1]; listIndex[j + 1] = tempInd; swaps++; } } if (swaps == 0) break; } //First, backup the best "listSize" number of entries. for (int k=(listSize-1); k>0; k--) { for (int i=0; i<polarParams->N; i++) { for (int j=0; j<(polarParams->n+1); j++) { bit[i][j][listIndex[(2*listSize-1)-k]]=bit[i][j][listIndex[k]]; llr[i][j][listIndex[(2*listSize-1)-k]]=llr[i][j][listIndex[k]]; } } } for (int k=(listSize-1); k>0; k--) { for (int i = 0; i < polarParams->crcParityBits; i++) { crcChecksum[i][listIndex[(2*listSize-1)-k]] = crcChecksum[i][listIndex[k]]; } } for (int k=(listSize-1); k>0; k--) crcState[listIndex[(2*listSize-1)-k]]=crcState[listIndex[k]]; //Copy the best "listSize" number of entries to the first indices. for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } for (int i = 0; i < polarParams->N; i++) { for (int j = 0; j < (polarParams->n + 1); j++) { bit[i][j][k] = bit[i][j][copyIndex]; llr[i][j][k] = llr[i][j][copyIndex]; } } } for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } for (int i = 0; i < polarParams->crcParityBits; i++) { crcChecksum[i][k]=crcChecksum[i][copyIndex]; } } for (int k = 0; k < listSize; k++) { if (k > listIndex[k]) { copyIndex = listIndex[(2*listSize-1)-k]; } else { //Use the backup. copyIndex = listIndex[k]; } crcState[k]=crcState[copyIndex]; } currentListSize = listSize; } for (int i=0; i<polarParams->crcParityBits; i++) { if (last1ind[i]==nonFrozenBit) { checkCrcBits=i; break; } } if ( checkCrcBits > (-1) ) { for (uint8_t i = 0; i < currentListSize; i++) { if (crcChecksum[checkCrcBits][i]!=extended_crc_scrambling_pattern[checkCrcBits]) { crcState[i]=0; //0=False, 1=True } } } for (uint8_t i = 0; i < currentListSize; i++) decoderIterationCheck+=crcState[i]; if (decoderIterationCheck==0) { //perror("[SCL polar decoder] All list entries have failed the CRC checks."); free(d_tilde); free(pathMetric); free(crcState); nr_free_uint8_3D_array(bit, polarParams->N, (polarParams->n+1)); nr_free_double_3D_array(llr, polarParams->N, (polarParams->n+1)); nr_free_uint8_2D_array(crcChecksum, polarParams->crcParityBits); return(-1); } nonFrozenBit++; decoderIterationCheck=0; checkCrcBits=-1; } } for (uint8_t i = 0; i < 2*listSize; i++) listIndex[i]=i; nr_sort_asc_double_1D_array_ind(pathMetric, listIndex, currentListSize); for (uint8_t i = 0; i < fmin(listSize, (pow(2,polarParams->crcCorrectionBits)) ); i++) { if ( crcState[listIndex[i]] == 1 ) { for (int j = 0; j < polarParams->N; j++) polarParams->nr_polar_U[j]=bit[j][0][listIndex[i]]; //Extract the information bits (û to ĉ) nr_polar_info_bit_extraction(polarParams->nr_polar_U, polarParams->nr_polar_CPrime, polarParams->information_bit_pattern, polarParams->N); //Deinterleaving (ĉ to b) nr_polar_deinterleaver(polarParams->nr_polar_CPrime, polarParams->nr_polar_B, polarParams->interleaving_pattern, polarParams->K); //Remove the CRC (â) for (int j = 0; j < polarParams->payloadBits; j++) polarParams->nr_polar_A[j]=polarParams->nr_polar_B[j]; break; } } free(d_tilde); free(pathMetric); free(crcState); nr_free_uint8_3D_array(bit, polarParams->N, (polarParams->n+1)); nr_free_double_3D_array(llr, polarParams->N, (polarParams->n+1)); nr_free_uint8_2D_array(crcChecksum, polarParams->crcParityBits); nr_free_uint8_2D_array(extended_crc_generator_matrix, polarParams->K); nr_free_uint8_2D_array(tempECGM, polarParams->K); /* * Return bits. */ nr_byte2bit_uint8_32(polarParams->nr_polar_A, polarParams->payloadBits, out); return(0); } void init_polar_deinterleaver_table(t_nrPolar_params *polarParams) { AssertFatal(polarParams->K > 32, "K = %d < 33, is not supported yet\n",polarParams->K); AssertFatal(polarParams->K < 129, "K = %d > 128, is not supported yet\n",polarParams->K); int bit_i,ip,ipmod64; int numbytes = polarParams->K>>3; int residue = polarParams->K&7; int numbits; if (residue>0) numbytes++; for (int byte=0; byte<numbytes; byte++) { if (byte<(polarParams->K>>3)) numbits=8; else numbits=residue; for (int i=0; i<numbits; i++) { // flip bit endian for B ip=polarParams->K - 1 - polarParams->interleaving_pattern[(8*byte)+i]; #if 0 printf("byte %d, i %d => ip %d\n",byte,i,ip); #endif ipmod64 = ip&63; AssertFatal(ip<128,"ip = %d\n",ip); for (int val=0; val<256; val++) { bit_i=(val>>i)&1; if (ip<64) polarParams->B_tab0[byte][val] |= (((uint64_t)bit_i)<<ipmod64); else polarParams->B_tab1[byte][val] |= (((uint64_t)bit_i)<<ipmod64); } } } } uint32_t polar_decoder_int16(int16_t *input, uint64_t *out, const t_nrPolar_params *polarParams) { int16_t d_tilde[polarParams->N];// = malloc(sizeof(double) * polarParams->N); nr_polar_rate_matching_int16(input, d_tilde, polarParams->rate_matching_pattern, polarParams->K, polarParams->N, polarParams->encoderLength); for (int i=0; i<polarParams->N; i++) { if (d_tilde[i]<-128) d_tilde[i]=-128; else if (d_tilde[i]>127) d_tilde[i]=128; } memcpy((void *)&polarParams->tree.root->alpha[0],(void *)&d_tilde[0],sizeof(int16_t)*polarParams->N); generic_polar_decoder(polarParams,polarParams->tree.root); //Extract the information bits (û to ĉ) uint64_t Cprime[4]= {0,0,0,0}; uint64_t B[4]= {0,0,0,0}; for (int i=0; i<polarParams->K; i++) Cprime[i>>6] = Cprime[i>>6] | ((uint64_t)polarParams->nr_polar_U[polarParams->Q_I_N[i]])<<(i&63); //Deinterleaving (ĉ to b) uint8_t *Cprimebyte = (uint8_t *)Cprime; if (polarParams->K<65) { B[0] = polarParams->B_tab0[0][Cprimebyte[0]] | polarParams->B_tab0[1][Cprimebyte[1]] | polarParams->B_tab0[2][Cprimebyte[2]] | polarParams->B_tab0[3][Cprimebyte[3]] | polarParams->B_tab0[4][Cprimebyte[4]] | polarParams->B_tab0[5][Cprimebyte[5]] | polarParams->B_tab0[6][Cprimebyte[6]] | polarParams->B_tab0[7][Cprimebyte[7]]; } else if (polarParams->K<129) { int len = polarParams->K/8; if ((polarParams->K&7) > 0) len++; for (int k=0; k<len; k++) { B[0] |= polarParams->B_tab0[k][Cprimebyte[k]]; B[1] |= polarParams->B_tab1[k][Cprimebyte[k]]; } } int len=polarParams->payloadBits; //int len_mod64=len&63; int crclen = polarParams->crcParityBits; uint64_t rxcrc=B[0]&((1<<crclen)-1); uint32_t crc; uint64_t Ar; AssertFatal(len<65,"A must be less than 65 bits\n"); if (len<=32) { Ar = (uint32_t)(B[0]>>crclen); uint8_t A32_flip[4]; uint32_t Aprime= (uint32_t)(Ar<<(32-len)); A32_flip[0]=((uint8_t *)&Aprime)[3]; A32_flip[1]=((uint8_t *)&Aprime)[2]; A32_flip[2]=((uint8_t *)&Aprime)[1]; A32_flip[3]=((uint8_t *)&Aprime)[0]; crc = (uint64_t)(crc24c(A32_flip,len)>>8); } else if (len<=64) { Ar = (B[0]>>crclen) | (B[1]<<(64-crclen));; uint8_t A64_flip[8]; uint64_t Aprime= (uint32_t)(Ar<<(64-len)); A64_flip[0]=((uint8_t *)&Aprime)[7]; A64_flip[1]=((uint8_t *)&Aprime)[6]; A64_flip[2]=((uint8_t *)&Aprime)[5]; A64_flip[3]=((uint8_t *)&Aprime)[4]; A64_flip[4]=((uint8_t *)&Aprime)[3]; A64_flip[5]=((uint8_t *)&Aprime)[2]; A64_flip[6]=((uint8_t *)&Aprime)[1]; A64_flip[7]=((uint8_t *)&Aprime)[0]; crc = (uint64_t)(crc24c(A64_flip,len)>>8); } #if 0 printf("A %llx B %llx|%llx Cprime %llx|%llx (crc %x,rxcrc %llx %d)\n", Ar, B[1],B[0],Cprime[1],Cprime[0],crc, rxcrc,polarParams->payloadBits); #endif out[0]=Ar; return(crc^rxcrc); }