/*---------------------------------------------------------------------------*
 *                                   IT++			             *
 *---------------------------------------------------------------------------*
 * Copyright (c) 1995-2001 by Tony Ottosson, Thomas Eriksson, Pål Frenger,   *
 * Tobias Ringström, and Jonas Samuelsson.                                   *
 *                                                                           *
 * Permission to use, copy, modify, and distribute this software and its     *
 * documentation under the terms of the GNU General Public License is hereby *
 * granted. No representations are made about the suitability of this        *
 * software for any purpose. It is provided "as is" without expressed or     *
 * implied warranty. See the GNU General Public License for more details.    *
 *---------------------------------------------------------------------------*/

/*! 
  \file 
  \brief Implementation of a CRC code class
  \author Tony Ottosson

  1.8 

  2003/05/22 08:55:20 
*/

#include "base/vec.h"
#include "base/binary.h"
#include "base/specmat.h"
#include "base/matfunc.h" //for reverse
#include "comm/crc.h"

namespace itpp { 

  void CRC_Code::set_generator(const bvec &poly)
  {
    //it_assert(poly(0) == 1 && poly(poly.size()-1) == 1, "CRC_Code::set_polynomial: not a valid polynomial");
    it_assert(poly(0) == 1, "CRC_Code::set_polynomial: not a valid polynomial");
    polynomial = poly;
    no_parity = polynomial.size()-1;
  }

#ifndef DOXYGEN_SHOULD_SKIP_THIS

  std::string crccode[18][2] = {
    {"CRC-4","1 1 1 1 1"},
    {"CRC-7","1 1 0 1 0 0 0 1"},
    {"CRC-8","1 1 1 0 1 0 1 0 1"},
    {"CRC-12","1 1 0 0 0 0 0 0 0 1 1 1 1"},
    {"CRC-24","1 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 1"},
    {"CRC-32","1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 1 1 1 0 0 0 1 0"},
    {"CCITT-4","1 0 0 1 1"},
    {"CCITT-5","1 1 0 1 0 1"},
    {"CCITT-6","1 0 0 0 0 1 1"},
    {"CCITT-16","1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1"},
    {"CCITT-32","1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 1 1 0 1 1 1"},
    {"WCDMA-8","1 1 0 0 1 1 0 1 1"},
    {"WCDMA-12","1 1 0 0 0 0 0 0 0 1 1 1 1"},
    {"WCDMA-16","1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1"},
    {"WCDMA-24","1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 1"},
    {"ATM-8","1 0 0 0 0 0 1 1 1"},
    {"ANSI-16","1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1"},
    {"SDLC-16","1 1 0 1 0 0 0 0 0 1 0 0 1 0 1 1 1"},
  };

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

  void CRC_Code::set_code(const std::string &code)
  {
    bvec poly;
    for (int i=0; i<18;i++) {
      if (crccode[i][0] == code)
	poly = bvec(crccode[i][1]);
    }

    if ( (code=="WCDMA-8") || (code=="WCDMA-12") || (code=="WCDMA-16") || (code=="WCDMA-24") ) {
      reverse_parity = true;
    }

    it_assert(poly.size()>0, "This CRC code doesn't exist in the tables");
    set_generator(poly);
  }

  // Not optimized for speed!
  void CRC_Code::parity(const bvec &in_bits, bvec &out)
  {
    bvec temp = concat(in_bits, zeros_b(no_parity));

    for (int i=0; i<temp.size()-polynomial.size()+1; i++) {
      if (temp(i) == 1) {
	temp.set_subvector(i,i+no_parity, temp(i,i+no_parity) + polynomial);
      }
    }   

    out = temp(temp.size()-no_parity,temp.size()-1);
  
    if (reverse_parity) {
      out = reverse( out );
    }

  }

  // Not optimized for speed
  bool CRC_Code::check_parity(const bvec &coded_bits)
  {
    int n = coded_bits.size();
    bvec temp;

    if (reverse_parity) {
      temp = concat( coded_bits.left(n-no_parity), reverse( coded_bits.right( no_parity ) ) );
    } else {
      temp = coded_bits;
    }

    for (int i=0; i<temp.size()-polynomial.size()+1; i++) { 
      if (temp(i) == 1) {
	temp.set_subvector(i,i+no_parity, temp(i,i+no_parity) + polynomial);
      }
    }   
  
    if ( temp(temp.size()-no_parity,temp.size()-1) == zeros_b(no_parity) )
      return true;
    else
      return false;
  }

  void CRC_Code::encode(const bvec &in_bits, bvec &out)
  {
    bvec p;
    parity(in_bits, p);
    out = concat(in_bits, p); 
  }

  bvec CRC_Code::encode(const bvec &in_bits)
  {
    bvec temp;
    encode(in_bits, temp);
    return temp;
  }

  bool CRC_Code::decode(const bvec &coded_bits, bvec &out) 
  {
    out = coded_bits(0, coded_bits.size()-no_parity-1); 
    if (check_parity(coded_bits)) {
      return true;
    } else
      return false;
  }

  bool CRC_Code::decode(bvec &coded_bits)
  {
    //coded_bits = coded_bits(0, coded_bits.size()-no_parity-1); <-- OLD CODE
    if (check_parity(coded_bits)) {
      return true;
    } else
      return false;
  }

} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1