#include "mw_dht11.h"

#include "stdint.h"
/* user define */

#include "public_diy.h"
#include "bsp_timer.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
/* 用户头文件定义 */
#define DHT11BUS_GPIO_PORT     (GPIOB)
#define DHT11BUS_GPIO_PIN      (GPIO_Pin_1)
#define DHT11BUS_GPIO_RCC	    (RCC_APB2Periph_GPIOB)

/* 用户安装函数 */
/*************************************************************************************
 * @brief    dht11用 延迟若干us 
 * @param[in/out] delay_us【参数注释】
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_delay_us(uint16_t delay_us)
{
    bsp_DelayUS(delay_us);
}
/*************************************************************************************
 * @brief    dht11用 延迟若干ms 
 * @param[in/out] delay_ms【参数注释】
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_delay_ms(uint16_t delay_ms)
{
    bsp_DelayMS(delay_ms);
}

/*************************************************************************************
 * @brief    dht11的单总线为 输出 高电平
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_output_high(void)
{
    // DHT11BUS_GPIO_PORT->BSRR = DHT11BUS_GPIO_PIN;
	// GPIO_SetBits(DHT11BUS_GPIO_PORT, DHT11BUS_GPIO_PIN);
	GPIO_WriteBit(DHT11BUS_GPIO_PORT, DHT11BUS_GPIO_PIN, (BitAction)1);
}
/*************************************************************************************
 * @brief    dht11的单总线为 输出 低电平
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_output_low(void)
{
    // DHT11BUS_GPIO_PORT->BRR = DHT11BUS_GPIO_PIN;
	GPIO_WriteBit(DHT11BUS_GPIO_PORT, DHT11BUS_GPIO_PIN, (BitAction)0);
}

/*************************************************************************************
 * @brief    将dht11的单总线改为输入
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_io_input(void)
{

	// GPIO_InitTypeDef GPIO_InitStructure;
	/* 打开GPIO时钟 */
	// RCC_APB2PeriphClockCmd(DHT11BUS_GPIO_RCC, ENABLE);

	// GPIO_InitStructure.GPIO_Pin = DHT11BUS_GPIO_PIN;
	// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;		/* 设为 输出开漏模式 */
	// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	/* IO口最大速度 */
	// GPIO_Init(DHT11BUS_GPIO_PORT, &GPIO_InitStructure);

// #if DHT11BUS_GPIO_PIN == GPIO_Pin_0
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFFFFF0;
//     DHT11BUS_GPIO_PORT->CRL |= 8;
// #endif

// #if DHT11BUS_GPIO_PIN == GPIO_Pin_1
    DHT11BUS_GPIO_PORT->CRL &= 0xFFFFFF0F;
    DHT11BUS_GPIO_PORT->CRL |= 4 << 4;
// #endif

// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_2
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFFF0FF;
//     DHT11BUS_GPIO_PORT->CRL |= 8 << 8;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_3
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFF0FFF;
//     DHT11BUS_GPIO_PORT->CRL |= 8 << 12;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_4
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFF0FFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 8 << 16;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_5
//     DHT11BUS_GPIO_PORT->CRL &= 0xFF0FFFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 8 << 20;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_6
    // DHT11BUS_GPIO_PORT->CRL &= 0xF0FFFFFF;
    // DHT11BUS_GPIO_PORT->CRL |= 8 << 24;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_7
//     DHT11BUS_GPIO_PORT->CRL &= 0x0FFFFFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 8 << 28;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_8
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFFFF0;
//     DHT11BUS_GPIO_PORT->CRH |= 8;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_9
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFFF0F;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 4;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_10
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFF0FF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 8;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_11
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFF0FFF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 12;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_12
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFF0FFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 16;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_13
//     DHT11BUS_GPIO_PORT->CRH &= 0xFF0FFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 20;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_14
//     DHT11BUS_GPIO_PORT->CRH &= 0xF0FFFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 24;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_15
//     DHT11BUS_GPIO_PORT->CRH &= 0x0FFFFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 8 << 28;
// #endif
}
/*************************************************************************************
 * @brief    将dht11的单总线改为输出
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
static void dht11_io_output(void)
{
// #if ((DHT11BUS_GPIO_PIN) == (GPIO_Pin_0))
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFFFFF0;
//     DHT11BUS_GPIO_PORT->CRL |= 3;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_1
    DHT11BUS_GPIO_PORT->CRL &= 0xFFFFFF0F;
    DHT11BUS_GPIO_PORT->CRL |= 7 << 4;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_2
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFFF0FF;
//     DHT11BUS_GPIO_PORT->CRL |= 3 << 8;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_3
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFFF0FFF;
//     DHT11BUS_GPIO_PORT->CRL |= 3 << 12;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_4
//     DHT11BUS_GPIO_PORT->CRL &= 0xFFF0FFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 3 << 16;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_5
//     DHT11BUS_GPIO_PORT->CRL &= 0xFF0FFFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 3 << 20;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_6
    // DHT11BUS_GPIO_PORT->CRL &= 0xF0FFFFFF;
    // DHT11BUS_GPIO_PORT->CRL |= 3 << 24;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_7
//     DHT11BUS_GPIO_PORT->CRL &= 0x0FFFFFFF;
//     DHT11BUS_GPIO_PORT->CRL |= 3 << 28;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_8
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFFFF0;
//     DHT11BUS_GPIO_PORT->CRH |= 3;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_9
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFFF0F;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 4;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_10
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFFF0FF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 8;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_11
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFFF0FFF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 12;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_12
//     DHT11BUS_GPIO_PORT->CRH &= 0xFFF0FFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 16;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_13
//     DHT11BUS_GPIO_PORT->CRH &= 0xFF0FFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 20;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_14
//     DHT11BUS_GPIO_PORT->CRH &= 0xF0FFFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 24;
// #elif DHT11BUS_GPIO_PIN == GPIO_Pin_15
//     DHT11BUS_GPIO_PORT->CRH &= 0x0FFFFFFF;
//     DHT11BUS_GPIO_PORT->CRH |= 3 << 28;
// #endif
}

/*************************************************************************************
 * @brief    获取dht11输出状态
 * @return uint8_t     【返回值注释】
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
uint8_t dht11_read_io_state(void)
{
    // return (uint8_t)(DHT11BUS_GPIO_PORT->ODR & DHT11BUS_GPIO_PIN);
    return GPIO_ReadInputDataBit(DHT11BUS_GPIO_PORT, DHT11BUS_GPIO_PIN);
}
/*************************************************************************************
 * @brief    dht11 单总线所需的gpio初始化
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
void dht11_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	/* 打开GPIO时钟 */
	RCC_APB2PeriphClockCmd(DHT11BUS_GPIO_RCC, ENABLE);

	GPIO_InitStructure.GPIO_Pin = DHT11BUS_GPIO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;		/* 设为 输出开漏模式 */
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	/* IO口最大速度 */
	GPIO_Init(DHT11BUS_GPIO_PORT, &GPIO_InitStructure);

	dht11_output_high();

}

/*************************************************************************************
 * @brief    dht11开始信号
 * @return uint8_t     RET_ERROR RET_OK
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
uint8_t dht11_start(void)
{
    uint8_t tmp_timer = 0;
    // 关总中断
    DISABLE_INT();
    //1.配置引脚为输出模式
	dht11_io_output();
	//2.把引脚电平拉低并持续20ms
	dht11_output_low();
	dht11_delay_ms(20);
	
	//3.把引脚电平拉高并持续20us
	dht11_output_high();
	dht11_delay_us(30);
	
	dht11_io_input();
	    // 等待dht11 拉低
    while(dht11_read_io_state() == 0 && tmp_timer < 101)
    {
        tmp_timer++;
        dht11_delay_us(1);
				__NOP();
    }
    if(tmp_timer > 100 || tmp_timer < 20)
    {
        return RET_ERROR;
    }
    // 检测是否存在第二个高电平
	tmp_timer = 0;	// 重置计数器
    while (dht11_read_io_state() == 1 && tmp_timer < 101)          // 等待DHT11释放总线，持续时间40~80us
	{
		tmp_timer++;               	// 总线拉高时计数
		dht11_delay_us(1);
	}
	ENABLE_INT();          // 开总中断
	if (tmp_timer>100 || tmp_timer<20) // 检测响应信号之后的高电平
	{
		return RET_ERROR;
	}

    // 均存在,  响应正常
	return RET_OK;
}

uint8_t dht11_read_byte(uint8_t *ret_byte)
{
    uint8_t tmp_timer = 0;
    uint8_t tmp_i;
	// uint8_t ret_byte = 0;

	DISABLE_INT();      // 关总中断
	dht11_io_input();
	for (tmp_i = 0; tmp_i < 8; tmp_i++)
	{
		/* 等待低电平，数据位前都有50us低电平时隙 */
		while (dht11_read_io_state() > 0 && tmp_timer < 101)
        {
            tmp_timer++;
            dht11_delay_us(1);
        }
        if(tmp_timer > 100)
		{
			return RET_ERROR;
		}
		tmp_timer = 0;
		/* 等待高电平，开始传输数据位 */
		while (dht11_read_io_state() == 0 && tmp_timer < 101)
		{
            tmp_timer++;
            dht11_delay_us(1);
        }
		if(tmp_timer > 100)
		{
			return RET_ERROR;
		}

		dht11_delay_us(40);

		*ret_byte <<= 1;         // 因高位在前，所以左移byt，最低位补0
		if (dht11_read_io_state() > 0)      // 将总线电平值读取到byt最低位中
		{
			*ret_byte |= 0x01;
		}
	}
	ENABLE_INT();      // 开总中断

	return RET_OK;
}


/**
  * @brief  读取数据
	* @param  Temp_H 温度整数部分
	* @param  Temp_L 温度小数部分
  * @param  Humi_H 湿度整数部分
  * @param  Humi_L 湿度小数部分
	* @retval 0-成功，1-失败
	*/
uint8_t mw_dht11_read_data(uint8_t *Temp_H,uint8_t *Temp_L,uint8_t *Humi_H,uint8_t *Humi_L)
{
	uint8_t sta = RET_ERROR;
	uint8_t i;
	uint8_t buf[5];

	if(dht11_start() == RET_OK)       // 检测响应信号
	{
		for(i=0;i<5;i++)            // 读取40位数据
		{
			sta = dht11_read_byte(&buf[i]); 	// 读取1字节数据
			if(sta == RET_ERROR)
			{
				return RET_ERROR;
			}
		}

		if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) // 校验成功
		{
			*Humi_H = buf[0]; // 湿度 整数部分数据
			*Humi_L = buf[1]; // 湿度 小数部分数据
			*Temp_H = buf[2]; // 温度 整数部分数据
			*Temp_L = buf[3]; // 温度 小数部分数据
			return RET_OK;
		}
		else
		{
			return RET_ERROR;
		}
	}
	else // 响应失败返回-1
	{
		*Temp_H = 0;
		*Temp_L = 0;
		*Humi_H = 0;
		*Humi_L = 0;

		return RET_ERROR;
	}  
}
/*************************************************************************************
 * @brief    dht11初始化
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
void mw_dht11_init(void)
{
    dht11_gpio_init();
}
