#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define RXBUFFER_MAX_LENGTH 80

typedef struct _obj
{
	int in;								//初始值
	int poly;							//多项式值
	int xorout;							//结果异或值
	int ret;							// crc校验值
	int length;							//需校验数据长度
	char rxBuffer[RXBUFFER_MAX_LENGTH]; //数据数组
} CRCObj;

int _OPEN_LOG = 0;

int _REFIN = 0;
int _REFOUT = 0;

CRCObj *objCreate(void);
void openLog(void);
void closeLog(void);
void objINIT(CRCObj *obj);
void bufferINIT(CRCObj *obj);
void setBitData(CRCObj *obj, int index, int data);
void setLength(CRCObj *obj, int length);
void figResult(CRCObj *obj);
int getResult(CRCObj *obj);
void setObjIn(CRCObj *obj, int tag);
void setObjPoly(CRCObj *obj, int tag);
void setObjXorOut(CRCObj *obj, int tag);
void setREFIN(int en);
void setREFOUT(int en);
unsigned short refout(unsigned short Data);
unsigned char refin(unsigned char Data);

CRCObj *objCreate(void)
{
	if (_OPEN_LOG)
		printf("======enter objCreate.\n");
	return (CRCObj *)malloc(sizeof(CRCObj));
}

void openLog(void)
{
	if (_OPEN_LOG)
		printf("======enter openLog.\n");
	_OPEN_LOG = 1;
	//printf("_OPEN_LOG:%d\n", _OPEN_LOG);
}
void closeLog(void)
{
	if (_OPEN_LOG)
		printf("======enter closeLog.\n");
	_OPEN_LOG = 0;
	//printf("_OPEN_LOG:%d\n", _OPEN_LOG);
}

void objINIT(CRCObj *obj)
{
	if (_OPEN_LOG)
		printf("======enter objINIT.\n");
	obj->in &= 0x00000000;
	obj->in |= 0x0000ffff;
	if (_OPEN_LOG)
		printf("the obj->in:%x\n", obj->in);
	obj->poly &= 0x00000000;
	obj->poly |= 0x00001021;
	if (_OPEN_LOG)
		printf("the obj->poly:%x\n", obj->poly);
	obj->xorout &= 0x00000000;
	obj->xorout |= 0x0000ffff;
	if (_OPEN_LOG)
		printf("the obj->xorout:%x\n", obj->xorout);
	obj->ret &= 0x00000000;
	if (_OPEN_LOG)
		printf("the obj->ret:%d\n", obj->ret);
	obj->length &= 0x00000000;
	if (_OPEN_LOG)
		printf("the obj->length:%d\n", obj->length);
	bufferINIT(obj);
}
void bufferINIT(CRCObj *obj)
{
	if (_OPEN_LOG)
		printf("======enter bufferINIT.\n");
	memset(obj->rxBuffer, 0, sizeof(obj->rxBuffer));
}
void setBitData(CRCObj *obj, int index, int data)
{
	if (_OPEN_LOG)
		printf("======enter setBitData.\n");
	if (index >= RXBUFFER_MAX_LENGTH)
	{
		if (_OPEN_LOG)
			printf("the index:%d too large.\n", index);
		return;
	}
	obj->rxBuffer[index] = data;
	if (_OPEN_LOG)
		printf("obj->rxBuffer[%d] = %x;\n", index, data);
	return;
}
void setLength(CRCObj *obj, int length)
{
	if (_OPEN_LOG)
		printf("======enter setLength.\n");
	obj->length = length;
	if (_OPEN_LOG)
		printf("obj->length:%d\n", obj->length);
	return;
}
void figResult(CRCObj *obj)
{
	if (_OPEN_LOG)
		printf("======enter figResult.\n");
	int len = 0;
	char cChar = 0;
	unsigned char ucIndex = 0;

	int uiIn = 0;
	int uiPoly = 0;
	int uiXorOut = 0;

	len = obj->length;
	uiIn = obj->in;
	uiPoly = obj->poly;
	uiXorOut = obj->xorout;

	while (len--)
	{
		if (_OPEN_LOG)
			printf("len:%x\n", len);
		cChar = obj->rxBuffer[ucIndex++];
		if (_REFIN)
			cChar = refin(cChar);
		if (_OPEN_LOG)
			printf("cChar-29:%x\n", cChar);
		uiIn ^= (cChar << 8);
		if (_OPEN_LOG)
			printf("uiIn-31:%x\n", uiIn);
		for (int i = 0; i < 8; i++)
		{
			if (uiIn & 0x8000)
				uiIn = (uiIn << 1) ^ uiPoly;
			else
				uiIn = uiIn << 1;
		}
		if (_OPEN_LOG)
			printf("uiIn-39:%x\n", uiIn);
	}
	if (_REFOUT)
		uiIn = refout(uiIn);
	obj->ret = uiIn ^ uiXorOut;
	if (_OPEN_LOG)
		printf("obj->ret:%x\n", obj->ret);
	return;
}

int getResult(CRCObj *obj)
{
	unsigned short temp = obj->ret;
	return temp;
}

//自定义设置crc初始值INIT
void setObjIn(CRCObj *obj, int tag)
{
	obj->in = tag;
	return;
}
//自定义设置多项式POLY
void setObjPoly(CRCObj *obj, int tag)
{
	obj->poly = tag;
	return;
}
//自定义设置结果异或值XOROUT
void setObjXorOut(CRCObj *obj, int tag)
{
	obj->xorout = tag;
	return;
}
void setREFIN(int en)
{
	_REFIN = en;
	return;
}
void setREFOUT(int en)
{
	_REFOUT = en;
	return;
}
int excObjResult(CRCObj *obj)
{
	unsigned short value = obj->ret;
	unsigned short ret = 0;
	unsigned short tempH = ((value & 0x00ff) << 8);
	unsigned short tempL = ((value & 0xff00) >> 8);
	if (_OPEN_LOG)
		printf("value:%x\n", value);
	if (_OPEN_LOG)
		printf("tempH:%x\n", tempH);
	if (_OPEN_LOG)
		printf("tempL:%x\n", tempL);
	ret = ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
	return ret;
}

unsigned short refout(unsigned short Data)
{
	unsigned short ret = 0;
	for (int i = 0; i < 16; i++)
	{
		if (Data & 0x8000)
			ret += 1 << i;
		Data <<= 1;
	}
	return ret;
}
unsigned char refin(unsigned char Data)
{
	unsigned char ret = 0;
	for (int i = 0; i < 8; i++)
	{
		if (Data & 0x80)
			ret += 1 << i;
		Data <<= 1;
	}
	return ret;
}
