#include "SHT20.h"


SHT20Var_t SHT20;

//---------- Defines -----------------------------------------------------------
// CRC 累加和校验常量
const uint32_t POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001

/*
************************************************************
*	函数名称：	SHT2x_CheckCrc
*
*	函数功能：	检查数据正确性
*
*	入口参数：	data：读取到的数据
*				nbrOfBytes：需要校验的数量
*				checksum：读取到的校对比验值
*
*	返回参数：	校验结果
*
*	说明：		0-成功		1-失败
************************************************************
*/
uint8_t SHT2x_CheckCrc(uint8_t *data, uint8_t nbrOfBytes, uint8_t checksum)
{
	uint8_t crc = 0;
	uint8_t bit = 0;
	uint8_t byteCtr = 0;

	//calculates 8-Bit checksum with given polynomial
	for(byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr) {
		crc ^= (data[byteCtr]);
		for ( bit = 8; bit > 0; --bit) {
			if (crc & 0x80) 
				crc = (crc << 1) ^ POLYNOMIAL;
			else 
				crc = (crc << 1);
		}
	}

	if(crc != checksum)
		return 1;
	return 0;
	
}

void delay_us(int dlycnt)
{
	for(int i = 0; i < dlycnt; i++) {
		uint8_t temp = 10;
		while(temp--);
	}
}

#ifdef I2C_SOFTWARE
#define ACK								0            //应答信号
#define NACK							1             //非应答信号
#define SHT20_IN_SDA			SHT20_I2C_SDA_Read() //读取SDA值
#define IIC_Delay()				delay_us(10)        //时钟延时

/*================================================================
[  Name  ]void IO_I2CInit(void)
[Function]I2C初始化 空闲状态
[  Notes ]
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
void IO_I2CInit(void)
{ 
 //
}

//
/*================================================================
[  Name  ]SHT20_I2C_SDA_Read
[Function]读取SDA数据线上值
[  Notes ]
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
uint8_t SHT20_I2C_SDA_Read(void)   
{
	SHT20_SDA_IN();
	if(SHT20_SDA_GET()) 
		return 1;
	else 
		return 0; 
}
 
/*================================================================
[  Name  ]I2CStart
[Function]开始
[  Notes ]
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
void I2CStart(void)
{
	//uint8_t retval;
	SHT20_SDA_OUT();	//设置成输出
	//SHT20_SCL_OUT();
	SHT20_I2C_SDA_HIGH();	//为SDA下降启动做准备
	SHT20_I2C_SCL_HIGH();	//在SCL高电平时，SDA为下降沿时候总线启动

	IIC_Delay();
	SHT20_I2C_SDA_LOW();	//突变，总线启动
	IIC_Delay();
	SHT20_I2C_SCL_LOW();
	IIC_Delay();
	
//SHT20_SDA_IN();	 //设置成输入
//	if(SHT20_IN_SDA)
//  {	 
//	  retval= NACK;
//  }
//	else
//	{
//		retval= ACK;
//	}
//	retval=retval;
}

/*================================================================
[  Name  ]I2CStop
[Function]结束
[  Notes ]
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
void I2CStop(void)
{    
	SHT20_SDA_OUT();	//设置成输出
	SHT20_I2C_SDA_LOW();	//为SDA上升做准备
	SHT20_I2C_SCL_LOW();

	IIC_Delay();
	SHT20_I2C_SCL_HIGH();	//在SCL高电平时，SDA为上升沿时候总线停止
	IIC_Delay();
	SHT20_I2C_SDA_HIGH();	//突变，总线停止
	IIC_Delay();
}

/*================================================================
[  Name  ]I2C_Write_Byte
[Function]写一个字节  返回ACK或NACK
[  Notes ]从高到低发
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
uint8_t I2C_Write_Byte(uint8_t Write_Byte)         //Sendbyte
{
	uint8_t i,retval=3;

	SHT20_SDA_OUT();	//设置成输出
	//SHT20_SCL_OUT() ;
	for(i = 0;i < 8;i++) {
		if(Write_Byte & 0x80)	
			SHT20_I2C_SDA_HIGH();	//判断发送位，先发送高位
		else
			SHT20_I2C_SDA_LOW();

		//IIC_Delay();
		SHT20_I2C_SCL_HIGH();	//为SCL下降做准备
		IIC_Delay();
		SHT20_I2C_SCL_LOW();	//突变，将数据位发送过去
		IIC_Delay();
		Write_Byte<<=1;	//数据左移一位
	}	//字节发送完成，开始接收应答信号
	IIC_Delay();
	SHT20_I2C_SDA_HIGH();	//释放数据线
	IIC_Delay();
	SHT20_SDA_IN();	//设置成输入
	//IIC_Delay();
	SHT20_I2C_SCL_HIGH();	//为SCL下降做准备
	IIC_Delay();

	if(SHT20_IN_SDA)	 
		retval= NACK;
	else 
		retval= ACK;

	SHT20_I2C_SCL_LOW();
	IIC_Delay();
	return retval;
}
//
/*================================================================
[  Name  ]I2C_Read_Byte
[Function]读一个字节，入库参数用于控制应答状态 ACK或NAC
[  Notes ]从高到低
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
uint8_t I2C_Read_Byte(uint8_t AckValue)//receivebyte
{
	uint8_t i;
	uint8_t RXDATA=0;
//	SHT20_SDA_OUT();	//设置成输出	
//	SHT20_I2C_SDA_HIGH();	//首先置数据线为高电平
//	SHT20_I2C_SCL_LOW();
	SHT20_SDA_IN();	//设置成输入

	for(i = 0;i < 8;i++) {
		SHT20_I2C_SCL_HIGH();	//突变
		IIC_Delay();
		RXDATA <<= 1;	//读入数据，高位在前	
		if(SHT20_IN_SDA)	RXDATA |= 0x01;	//收到高电平
		else RXDATA &= 0xfe;	
		IIC_Delay();
		SHT20_I2C_SCL_LOW();
		IIC_Delay();
	}	//数据接收完成

	SHT20_SDA_OUT();
	if(AckValue)
		SHT20_I2C_SDA_HIGH();
	else
		SHT20_I2C_SDA_LOW();

	IIC_Delay();
	SHT20_I2C_SCL_HIGH();
	IIC_Delay();
	SHT20_I2C_SCL_LOW();
	IIC_Delay();

	return RXDATA;	//返回读取到的数据
}

/*================================================================
[  Name  ]SHT20_SoftReset
[Function]SHT20软件复位
[  Notes ]从高到低
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
void SHT20_Reset(void)                    
{
	// IO_I2CInit();                       //I2C initialize
	I2CStart();                      //start I2C
	I2C_Write_Byte(SHT20_ADDRESS&0xfe);  //I2C address + write
	I2C_Write_Byte(0xfe);                 //soft reset
	I2CStop();                       //stop I2C
}

/*================================================================
[  Name  ]SET_Resolution
[Function]写寄存器 设置分辨率
[  Notes ]从高到低
[ Author ]LZH
[  Data  ]2016.06.22
================================================================*/
void SET_Resolution(void)                    
{
	I2CStart();																			//Start I2C 
	if(I2C_Write_Byte(SHT20_ADDRESS&0xfe) == ACK) {			//I2C address + write + ACK
		if(I2C_Write_Byte(0xe6) == ACK) {							//写用户寄存器
			if(I2C_Write_Byte(0x83) == ACK) 
				__NOP();																		//设置分辨率  11bit RH% 测量时间:12ms(typ.) & 11bit T测量时间:9ms(typ.) 
		}
	}
	I2CStop();																			//Stop I2C        
}
 
/*================================================================
[  Name  ]ReadSht20
[Function]非主机模式，读取温湿度值
[  Notes ]入口控制读取温度或湿度 复位需要15ms 温度转换最大需要85ms
[ Author ]LZH  SHT20上电后等待20ms 再读取sht20
[  Data  ]2016.06.22
================================================================*/
float SHT2x_MeasureHM(uint8_t whatdo)
{
	float temp;
	uint8_t MSB,LSB,checksum=0,checktemp[2];
	float Humidity,Temperature;
	uint32_t waitt= 1000;  
	//SET_Resolution(); //此处之前出过问题 所以屏蔽掉

	I2CStart();        
	if(I2C_Write_Byte(SHT20_ADDRESS&0xfe)==ACK) {									//I2C address + write + ACK
		if(I2C_Write_Byte(whatdo)==ACK) {												//Command
			do{
				delay_us(100); //加入超时
				I2CStart();    
				if(--waitt==0)	
					break;
			} while(I2C_Write_Byte(SHT20_ADDRESS|0x01) == NACK);			//I2C address + read        + NACK 
			
			if(waitt != 0) {
				MSB = I2C_Read_Byte(ACK);															//Data(MSB)
				LSB = I2C_Read_Byte(ACK);															//Data(LSB)
				checksum=I2C_Read_Byte(NACK);													//Checksum  + NACK 累加和校验值
				I2CStop();																						//Stop I2C
				checktemp[0]=MSB;
				checktemp[1]=LSB;
				if(SHT2x_CheckCrc(checktemp,2,checksum)) {						//累加和校验成功
					LSB &= 0xfc;																				//Data (LSB) 后两位清零
					temp = MSB*256 + LSB;																//十六进制转十进制
					if (whatdo==((uint8_t)0xf5)) {													//No Hold Master Mode,read humidity       
						/*-- calculate relative humidity [%RH] --*/ 
						Humidity =(temp*125)/65536-6;											//公式: RH%= -6 + 125 * SRH/2^16														
						return Humidity;																	//返回:humidity
					}                                                                                                  
					else{																								//No Hold Master Mode,read temperature        
						/*-- calculate temperature [℃] --*/
						Temperature = (temp*175.72)/65536-46.85;						//公式:T= -46.85 + 175.72 * ST/2^16
						return Temperature;																	//返回:temperature
					}
				}
			}
		}
	}
	I2CStop();  //CT add
	return 0;
}
//
/********************************************************
[  Name  ]GetMiddleNum
[Function] 中值滤波
[  Notes ] 传入数据buf bArray, iFilterLen滤波数据长度
[ Author ] CSDN
[  Data  ]2018.10.25
 
**********************************************************/

float GetMiddleNum(float * bArray, uint8_t iFilterLen)
{
	uint8_t i,j;// 循环变量
	float bTemp;

	if(iFilterLen>100)
		return 0;
	// 用冒泡法对数组进行排序
	for (j = 0; j < iFilterLen - 1; j ++) {
		for (i = 0; i < iFilterLen - j - 1; i ++) {
			if (bArray[i] > bArray[i + 1]) {
				// 互换
				bTemp = bArray[i];
				bArray[i] = bArray[i + 1];
				bArray[i + 1] = bTemp;
			}
		}
	}
	// 计算中值
	if ((iFilterLen & 1) > 0) {
		// 数组有奇数个元素，返回中间一个元素
		bTemp = bArray[(iFilterLen -1) / 2];
	}
	else {
		// 数组有偶数个元素，返回中间两个元素平均值
		bTemp = (bArray[iFilterLen / 2-1] + bArray[iFilterLen / 2 ]) / 2;
	}
	return bTemp;
}
//
/********************************************************
[  Name  ]ReadSht20_Medium
[Function] 获取中值
[  Notes ] 读取完后关闭上拉 设为低 (解决干扰问题)
[ Author ]  
[  Data  ]2018.10.25
 
**********************************************************/
float ReadSht20_Medium (void)
{
	float arry3[3];
	//SHT20_I2C_SET_PULL_UP();  //开启引脚上拉
	for(uint8_t ui=0; ui<3; ui++) {
		arry3[ui]= SHT2x_MeasureHM(SHT20_Measurement_T_HM);
		delay_us(20);
	//printf("sht origin %.2f \r\n",arry3[ui]);
	}
	float retv = GetMiddleNum(arry3, 3);

#ifdef I2C_SOFTWARE
	//SHT20_I2C_SET_PULL_NO();  //关闭上拉
	SHT20_I2C_LOW();          //读取完温度后拉低
#endif
	return retv;
}

#else

/*
************************************************************
*	函数名称：	SHT20_reset
*
*	函数功能：	SHT20复位
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明：
************************************************************
*/
void SHT20_Reset(void)
{
	uint8_t Data = SHT20_SOFT_RESET;
	Sht20_Reg_Write(SHT20_ADDRESS, &Data, 1);
	Sht20_Delay(15);
}

/*
************************************************************
*	函数名称：	SHT20_read_user_reg
*
*	函数功能：	SHT20读取用户寄存器
*
*	入口参数：	无
*
*	返回参数：	读取到的用户寄存器的值
*
*	说明：
************************************************************
*/
uint8_t  SHT20_read_user_reg(void)
{
	uint8_t val = 0;
	uint8_t reg = SHT20_READ_REG;
	Sht20_Read(SHT20_ADDRESS, &reg, &val, 1);
	return val;
}

/*
************************************************************
*	函数名称：	SHT2x_CalcTemperatureC
*
*	函数功能：	温度计算
*
*	入口参数：	u16sT：读取到的温度原始数据
*
*	返回参数：	计算后的温度数据
*
*	说明：
************************************************************
*/
float SHT2x_CalcTemperatureC(uint16_t u16sT)
{
	float temperatureC = 0;            // variable for result

	u16sT &= ~0x0003;           // clear bits [1..0] (status bits)
	//-- calculate temperature [℃] --
	temperatureC = -46.85 + 175.72 / 65536 * (float)u16sT; //T= -46.85 + 175.72 * ST/2^16

	return temperatureC;
}

/*
************************************************************
*	函数名称：	SHT2x_CalcRH
*
*	函数功能：	湿度计算
*
*	入口参数：	u16sRH：读取到的湿度原始数据
*
*	返回参数：	计算后的湿度数据
*
*	说明：
************************************************************
*/
float SHT2x_CalcRH(uint16_t u16sRH)
{
	float humidityRH = 0;              // variable for result

	u16sRH &= ~0x0003;          // clear bits [1..0] (status bits)
	//-- calculate relative humidity [%RH] --
	//humidityRH = -6.0 + 125.0/65536 * (float)u16sRH; // RH= -6 + 125 * SRH/2^16
	humidityRH = ((float)u16sRH * 0.00190735) - 6;

	return humidityRH;
}

/*
************************************************************
*	函数名称：	SHT2x_MeasureHM
*
*	函数功能：	测量温湿度
*
*	入口参数：	cmd：测量温度还是湿度
*
*	返回参数：	测量结果
*
*	说明：
************************************************************
*/
float SHT2x_MeasureHM(uint8_t cmd)
{
	uint8_t  checksum = 0;  //checksum
	uint8_t  data[3];    //data array for checksum verification
	uint16_t tmp = 0;
	float t = 0;
	
	Sht20_Read(SHT20_ADDRESS, &cmd, data, 3);
	checksum = data[2];
	if(SHT2x_CheckCrc(data, 2, checksum) == 0) {
		tmp = (data[0] << 8) + data[1];
		if(cmd == SHT20_Measurement_T_NHM) 
			t = SHT2x_CalcTemperatureC(tmp);
		else 
			t = SHT2x_CalcRH(tmp);
	}

	return t;
}


#endif

/*
************************************************************
*	函数名称：	SHT20_GetValue
*
*	函数功能：	获取温湿度数据
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明：		温湿度结果保存在SHT20结构体里
************************************************************
*/
void SHT20_GetValue(float *Tempreture, float *Humidity)
{
	if(Tempreture != NULL) {
		*Tempreture = SHT20.Tempreture;
	}
	if(Humidity != NULL) {
		*Humidity = SHT20.Humidity;
	}
	//SHT20_reset();
}

void SHT20Start(void)
{
	memset(&SHT20, 0x00, sizeof(SHT20));
	SHT20.Sht20Status = SHT20_INIT;
}
void SHT20LoopHandler(void)
{
	uint8_t ret;
	uint8_t rData[3];
	
	switch(SHT20.Sht20Status) {
		case SHT20_IDLE:
			break;
		
		case SHT20_INIT:
			SHT20_Reset();
			SHT20.Sht201mSDelayCnt = 200;
			SHT20.Sht20Status = SHT20_READ_HUMI;
			break;
		
		case SHT20_READ_TEMPR:
			if(SHT20.Sht201mSDelayCnt > 0)
				break;
			SHT20.Cmd = SHT20_Measurement_T_NHM;
			ret = SHT20_StartMeas(SHT20_ADDRESS, &SHT20.Cmd);
			if(ret == true) {
				SHT20.Sht201mSDelayCnt = 90;
				SHT20.Sht20Status = SHT20_READ_DATA;
			}
			else {
				SHT20.Sht201mSDelayCnt = 1000;
				SHT20.Sht20Status = SHT20_INIT;
			}
			break;
		
		case SHT20_READ_HUMI:
			if(SHT20.Sht201mSDelayCnt > 0)
				break;
			SHT20.Cmd = SHT20_Measurement_RH_NHM;
			ret = SHT20_StartMeas(SHT20_ADDRESS, &SHT20.Cmd);
			if(ret == true) {
				SHT20.Sht201mSDelayCnt = 90;
				SHT20.Sht20Status = SHT20_READ_DATA;
			}
			else {
				SHT20.Sht201mSDelayCnt = 1000;
				SHT20.Sht20Status = SHT20_INIT;
			}
			break;
			
		case SHT20_READ_DATA:
			if(SHT20.Sht201mSDelayCnt > 0)
				break;
			ret = SHT20_Readata(SHT20_ADDRESS, rData, 3);
			if(ret == true) {
				if(SHT2x_CheckCrc(rData, 2, rData[2]) == 0) {
					uint16_t tmp = (rData[0] << 8) + rData[1];
					if(SHT20.Cmd == SHT20_Measurement_T_NHM) {
						SHT20.Tempreture = SHT2x_CalcTemperatureC(tmp);
						SHT20.Sht20Status = SHT20_READ_HUMI;
					}
					else {
						SHT20.Humidity = SHT2x_CalcRH(tmp);
						SHT20.Sht20Status = SHT20_READ_TEMPR;
					}
					SHT20.Sht201mSDelayCnt = 5;
				}
			}
			else {
				SHT20.Sht201mSDelayCnt = 1000;
				SHT20.Sht20Status = SHT20_INIT;
			}
	}
}

void SHT201mSRoutine(void)
{
	if(SHT20.Sht201mSDelayCnt > 0)
		SHT20.Sht201mSDelayCnt--;
}

