/*---------------------------------------------------------------------------*
 *                                   IT++			             *
 *---------------------------------------------------------------------------*
 * Copyright (c) 1995-2004 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 Hamming code class
  \author Tony Ottosson

  1.7

  2004/08/17 09:27:24
*/

#include "base/binary.h"
#include "base/scalfunc.h"
#include "base/converters.h"
#include "base/matfunc.h"
#include "comm/hammcode.h"

namespace itpp { 

  Hamming_Code::Hamming_Code(short m)
  {
    n = round_i(pow(2,m)) - 1;
    k = round_i(pow(2,m)) - m - 1;
    H.set_size(n-k,n,0); 	
    G.set_size(k,n,0);	
    generate_H(); // generate_H must be run before generate_G
    generate_G();
  }

  void Hamming_Code::generate_H(void)
  {
    short i, j, NextPos;
    char NotUsed;
    bvec temp;
    svec indexes(n);
    indexes.zeros();
	
    for (i=1; i<=n-k; i++) { indexes(i-1) = round_i(pow(2,n-k-i)); }
    NextPos = n-k;
    for (i=1; i<=n; i++) {
      NotUsed = 1;
      for (j=0; j<n; j++) 
	if (i == indexes(j)) { NotUsed = 0; }
      if (NotUsed) { indexes(NextPos) = i; NextPos = NextPos + 1; }
    }
			
    for (i=0; i<n; i++) {	
      temp = dec2bin(n-k,indexes(i)); //<-CHECK THIS OUT!!!!
      for (j = 0; j < (n-k); j++) {
	H(j,i) = temp(j);
      }
    }
  }

  void Hamming_Code::generate_G(void)
  {
    short i, j;
    for (i=0; i<k; i++) {
      for(j=0; j<n-k; j++) 
	G(i,j) = H(j,i+n-k);
    }
	
    for (i=0; i<k; i++) {
      for (j=n-k; j<n; j++) 
	G(i,j) = 0;
    }
	
    for (i=0; i<k; i++)
      G(i,i+n-k) = 1;
  }

  void Hamming_Code::encode(const bvec &uncoded_bits, bvec &coded_bits)
  {
    int length = uncoded_bits.length();
    int Itterations = (int)floor( float(length) / k );
    bmat Gt = G.T();
    int i;
    
    coded_bits.set_size(Itterations * n, false);
    //Code all codewords
    for (i=0; i<Itterations; i++) 
      coded_bits.replace_mid(n*i, Gt * uncoded_bits.mid(i*k,k) );
  }

  bvec Hamming_Code::encode(const bvec &uncoded_bits)
  {
    bvec coded_bits;
    encode(uncoded_bits, coded_bits);
    return coded_bits;
  }

  void Hamming_Code::decode(const bvec &coded_bits, bvec &decoded_bits)
  {
    int length = coded_bits.length();
    int Itterations = (int)floor( float(length) / n );
    svec Hindexes(n);
    bvec temp(n-k);
    bvec coded(n), syndrome(n-k);
    short  isynd, errorpos=0;
    int i, j;
    
    decoded_bits.set_size(Itterations*k, false);

    for (i=0; i<n; i++) {
      for (j=0; j<n-k; j++) 
	temp(j) = H(j,i);
      Hindexes(i) = bin2dec(temp); 
    }
	
    //Decode all codewords
    for (i=0; i<Itterations; i++) {
      coded = coded_bits.mid(i*n,n);
      syndrome = H * coded;
      isynd = bin2dec(syndrome); 
      if (isynd != 0) {
	for (j=0; j<n; j++) 
	  if (Hindexes(j) == isynd) { errorpos = j; };
	coded(errorpos) += 1;
      }
      decoded_bits.replace_mid(k*i,coded.right(k));
    }
  }

  bvec Hamming_Code::decode(const bvec &coded_bits)
  {
    bvec decoded_bits;
    decode(coded_bits, decoded_bits);
    return decoded_bits;
  }



} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1