#include "hamming.h"
#include "math.h"
#include <stdbool.h>
#include <string.h>

//编码
unsigned char HMBM_74(unsigned char a)
{

	unsigned char b =0;

	b = a & 0x0F;
	b = b <<0x03;

	if(b&0x08){b=b^0x03;}
	if(b&0x10){b=b^0x05;}
	if(b&0x20){b=b^0x06;}
	if(b&0x40){b=b^0x07;}
	
	return(b & 0x7F);

}

//解码
unsigned char  HMYM_74(unsigned char  a)
{

	unsigned char b=0,c=0;
	b = a;
	c = 0;
	if(b&0x40) {c = c^0x07 ;}
	if(b&0x20) {c = c^0x06 ;}
	if(b&0x10) {c = c^0x05 ;}
	if(b&0x08) {c = c^0x03 ;}
	if(b&0x04) {c = c^0x04 ;}
	if(b&0x02) {c = c^0x02 ;}
	if(b&0x01) {c = c^0x01 ;}

	switch(c){
		case 0 :b = b >> 3 ;break ;
		case 1 :b = b >> 3 ;break ;
		case 2 :b = b >> 3 ;break ;
		case 3 :b = (b^0x08) >> 3 ;break ;
		case 4 :b = b >> 3 ;break ;
		case 5 :b = (b^0x10) >> 3 ;break ;
		case 6 :b = (b^0x20) >> 3 ;break ;
		case 7 :b = (b^0x40) >> 3 ;break ;
	}

	return (b & 0x0F);
}



//对u32数据编码
//data:输入的待编码数据
//code:编码后生成的数据（1字节的原始数据生成2字节的编码数据）
void HM_encode_u32(uint32_t data, uint32_t *code)
{
	int i,j;
	uint32_t temp = 0;
	uint8_t data_char[8] = {0};
	uint8_t data_encode[8] = {0};
	memset(code,0,2);
	
//	原始数据拆分:
	for(i = 0; i < 8; i++)
	{
		data_char[i] = (data>>(4*(7-i))) & 0x0f;
	}
	
	//编码
	for(i = 0; i < 8; i++)
	{
		data_encode[i] = HMBM_74(data_char[i]);
	}
	
	//编码后数据合成
	for(i = 0; i < 2; i++)
	{
		for(j = 0; j < 4; j++)
		{
			temp = data_encode[i*4+j];
			code[i] |= temp<<(3-j)*8;
		}
	}
}

//对u32数据解码
uint32_t HM_decode_u32(uint32_t *data)
{
	int i,j;
	uint32_t temp = 0;
	uint32_t data_de=0;
	uint8_t data_temp[8] = {0};
	uint8_t data_decode[8] = {0};
	
	//	原始数据拆分:
	for(i = 0; i < 2; i++)
	{
		for(j = 0; j < 4; j++)
		{
			data_temp[i*4+j] = (data[i]>>(3-j)*8) & 0xff;
		}
	}
	
	//解码
	for(i = 0; i < 8; i++)
	{
		data_decode[i] = HMYM_74(data_temp[i]);
	}
	
	//解码后数据合成
	for(i = 0; i < 8; i++)
	{
		temp = data_decode[i];
		data_de |= temp<<4*(7-i);
	}
	
	return data_de;
}



//汉明码编码（一个字节）
void HM_encode_char(uint8_t data, uint8_t *code)
{
    int i;
	uint8_t data_char[2] = {0};
	memset(code,0,2);
	
//	原始数据拆分:
    data_char[0] = data & 0x0f;
    data_char[1] = (data>>4) & 0x0f;

	//编码
	for(i = 0; i < 2; i++)
	{
		code[i] = HMBM_74(data_char[i]);
	}
}

//汉明码解码(一个字节)
uint8_t HM_decode_char(uint8_t *code)
{
    int i;
    uint8_t data = 0;
	uint8_t data_decode[2] = {0};
	
	//解码
	for(i = 0; i < 2; i++)
	{
		data_decode[i] = HMYM_74(code[i]);
	}
	
	//解码后数据合成
    data |= data_decode[0];
    data |= data_decode[1]<<4;

	return data;
}

//汉明码编码（多字节）
//返回编码后的字节数
void HM_encode(uint8_t *src, uint8_t *des, uint16_t size)
{
    int i;
    memset(des,0,size*2);
    for(i = 0; i < size; i++)
    {
        HM_encode_char(src[i],des+2*i);
    }
}

//汉明码解码（多个字节）
void HM_decode(uint8_t *src, uint8_t *des, uint16_t size)
{
    int i;
    memset(des,0,size/2);
    for(i = 0; i < size; i=i+2)
    {
        des[i/2] = HM_decode_char(src+i);
    }
}


#define NUM 8
void hamming_test(uint8_t num) 
{
	#if 0
	int i,j,temp,temp_bit;
    unsigned char coder_T[NUM] = {0};
    unsigned char encoder_T[NUM] = {0};
    unsigned char decoder_T[NUM] = {0};

    srand(TickCounter);
    printf("汉明码测试:\n");
    printf("原始数据:");

	//生成原数据
    for(i = 0; i < NUM; i++)
    {
        coder_T[i] = rand()%0x10;
        printf("%02x ",coder_T[i]);
    }
    printf("\n");

	//编码
	for(i = 0; i < NUM; i++)
	{
		encoder_T[i] = HMBM_74(coder_T[i]);
	}
	
    printf("编码数据:");
    for(i = 0; i < NUM; i++)
    {
        printf("%02x ",encoder_T[i]);
    }
    printf("\n");
	
	printf("共修改%d位\n",num);
	for(i = 0; i < num; i++)
	{
		temp = rand()%(NUM*8);
		j = temp/8;
		temp_bit = temp%8;
		
		encoder_T[j] ^= 1<<temp_bit;
		
		printf("修改第%02d位\n",temp);
	}
	printf("修改数据:");
	for(i = 0; i < NUM; i++)
    {
        printf("%02x ",encoder_T[i]);
    }
    printf("\n");

	//解码
	for(i = 0; i < NUM; i++)
	{
		decoder_T[i] = HMYM_74(encoder_T[i]);
	}
	
    printf("解码数据:");
    for(i = 0; i < NUM; i++)
    {
        printf("%02x ",decoder_T[i]);
    }
    printf("\n");
	#endif
	
	uint32_t data = 0, data_de = 0;
	uint32_t data_en[2] = {0};
	
	srand(0);
    printf("汉明码测试:\n");
    
	data = rand()%0xffffffff;
	printf("原始数据:%08x\n",data);
	
	HM_encode_u32(data,data_en);
	printf("编码数据:%08x, %08x\n",data_en[0],data_en[1]);
	
	data_de = HM_decode_u32(data_en);
	printf("解码数据:%08x\n",data_de);
}

