/** * * \section COPYRIGHT * * Copyright 2013-2015 Software Radio Systems Limited * * \section LICENSE * * This file is part of the srsLTE library. * * srsLTE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsLTE 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 Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #include #include #include #include "srslte/utils/bit.h" #include "srslte/fec/crc.h" void gen_crc_table(srslte_crc_t *h) { int i, j, ord = (h->order - 8); uint64_t bit, crc; for (i = 0; i < 256; i++) { crc = ((uint64_t) i) << ord; for (j = 0; j < 8; j++) { bit = crc & h->crchighbit; crc <<= 1; if (bit) crc ^= h->polynom; } h->table[i] = crc & h->crcmask; } } uint64_t crctable(srslte_crc_t *h, uint8_t byte) { // Polynom order 8, 16, 24 or 32 only. int ord = h->order - 8; uint64_t crc = h->crcinit; crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte]; h->crcinit = crc; return (crc & h->crcmask); } uint64_t reversecrcbit(uint32_t crc, int nbits, srslte_crc_t *h) { uint64_t m, rmask = 0x1; for (m = 0; m < nbits; m++) { if ((rmask & crc) == 0x01) crc = (crc ^ h->polynom) >> 1; else crc = crc >> 1; } return (crc & h->crcmask); } int srslte_crc_set_init(srslte_crc_t *crc_par, uint64_t crc_init_value) { crc_par->crcinit = crc_init_value; if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) { printf("ERROR, invalid crcinit in crc_set_init().\n"); return -1; } return 0; } int srslte_crc_init(srslte_crc_t *h, uint32_t crc_poly, int crc_order) { // Set crc working default parameters h->polynom = crc_poly; h->order = crc_order; h->crcinit = 0x00000000; // Compute bit masks for whole CRC and CRC high bit h->crcmask = ((((uint64_t) 1 << (h->order - 1)) - 1) << 1) | 1; h->crchighbit = (uint64_t) 1 << (h->order - 1); // check parameters if (h->order % 8 != 0) { fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n", h->order); return -1; } if (srslte_crc_set_init(h, h->crcinit)) { fprintf(stderr, "Error setting CRC init word\n"); return -1; } // generate lookup table gen_crc_table(h); return 0; } uint32_t srslte_crc_checksum(srslte_crc_t *h, uint8_t *data, int len) { int i, k, len8, res8, a = 0; uint32_t crc = 0; uint8_t *pter; srslte_crc_set_init(h, 0); // Pack bits into bytes len8 = (len >> 3); res8 = (len - (len8 << 3)); if (res8 > 0) { a = 1; } // Calculate CRC for (i = 0; i < len8 + a; i++) { pter = (uint8_t *) (data + 8 * i); uint8_t byte; if (i == len8) { byte = 0x00; for (k = 0; k < res8; k++) { byte |= ((uint8_t) *(pter + k)) << (7 - k); } } else { byte = (uint8_t) (srslte_bit_pack(&pter, 8) & 0xFF); } crc = crctable(h, byte); } // Reverse CRC res8 positions if (a == 1) { crc = reversecrcbit(crc, 8 - res8, h); } //Return CRC value return crc; } // len is multiple of 8 uint32_t srslte_crc_checksum_byte(srslte_crc_t *h, uint8_t *data, int len) { int i; uint32_t crc = 0; srslte_crc_set_init(h, 0); // Calculate CRC for (i = 0; i < len/8; i++) { crc = crctable(h, data[i]); } return crc; } uint32_t srslte_crc_attach_byte(srslte_crc_t *h, uint8_t *data, int len) { uint32_t checksum = srslte_crc_checksum_byte(h, data, len); // Add CRC for (int i=0;iorder/8;i++) { data[len/8+(h->order/8-i-1)] = (checksum&(0xff<<(8*i)))>>(8*i); } return checksum; } /** Appends crc_order checksum bits to the buffer data. * The buffer data must be len + crc_order bytes */ uint32_t srslte_crc_attach(srslte_crc_t *h, uint8_t *data, int len) { uint32_t checksum = srslte_crc_checksum(h, data, len); // Add CRC uint8_t *ptr = &data[len]; srslte_bit_unpack(checksum, &ptr, h->order); return checksum; }