// #include "stm32f103xb.h"

//网络设备驱动
#include "esp8266.h"

//硬件驱动
#include "main.h"
#include "usart.h"


//C库
#include <string.h>
#include <stdio.h>

#include "cmsis_os.h"
#include "cmsis_os2.h"


// #define ESP8266_WIFI_INFO		"AT+CWJAP=\"Timo\",\"11223344\"\r\n"
#define ESP8266_ONENET_INFO		"AT+CIPSTART=\"TCP\",\"183.230.40.96\",1883\r\n"

unsigned char esp8266_buf[128];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;

void Usart_SendString(UART_HandleTypeDef* huart, unsigned char* str, unsigned short len)
{
    unsigned short count = 0;

    HAL_UART_Transmit(huart, (uint8_t*)str, len, 0xffff);
    while (HAL_UART_GetState(huart) == HAL_UART_STATE_BUSY_TX);
}

//==========================================================
//	函数名称:	ESP8266_Clear
//
//	函数功能:	清空缓存
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:
//==========================================================
void ESP8266_Clear(void)
{
    memset(esp8266_buf, 0, sizeof(esp8266_buf));
    esp8266_cnt = 0;
}

//==========================================================
//	函数名称:	ESP8266_WaitRecive
//
//	函数功能:	等待接收完成
//
//	入口参数:	无
//
//	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
//
//	说明:		循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{
    if (esp8266_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
        return REV_WAIT;

    if (esp8266_cnt == esp8266_cntPre) //如果上一次的值和这次相同,则说明接收完毕
    {
        esp8266_cnt = 0; //清0接收计数

        return REV_OK; //返回接收完成标志
    }

    esp8266_cntPre = esp8266_cnt; //置为相同

    return REV_WAIT; //返回接收未完成标志
}

//==========================================================
//	函数名称:	ESP8266_SendCmd
//
//	函数功能:	发送命令
//
//	入口参数:	cmd:命令
//				res:需要检查的返回指令
//
//	返回参数:	0-成功	1-失败
//
//	说明:
//==========================================================
_Bool ESP8266_SendCmd(char* cmd, char* res)
{
    unsigned char timeOut = 200;

    Usart_SendString(&huart2, (unsigned char*)cmd, strlen((const char*)cmd));

    while (timeOut--)
    {
        if (ESP8266_WaitRecive() == REV_OK) //如果收到数据
        {
            if (strstr((const char*)esp8266_buf, res) != NULL) //如果检索到关键词
            {
                ESP8266_Clear(); //清空缓存

                return 0;
            }
        }

        HAL_Delay(10);
    }

    return 1;
}

//==========================================================
//	函数名称:	ESP8266_SendData
//
//	函数功能:	发送数据
//
//	入口参数:	data:数据
//				len:长度
//
//	返回参数:	无
//
//	说明:
//==========================================================
void ESP8266_SendData(unsigned char* data, unsigned short len)
{
    char cmdBuf[32];

    ESP8266_Clear(); //清空接收缓存
    sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //发送命令
    if (!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’时可以发送数据
    {
        Usart_SendString(&huart2, data, len); //发送设备连接请求数据
    }
}

//==========================================================
//	函数名称:	ESP8266_GetIPD
//
//	函数功能:	获取平台返回的数据
//
//	入口参数:	等待的时间(乘以10ms)
//
//	返回参数:	平台返回的原始数据
//
//	说明:		不同网络设备返回的格式不同,需要去调试
//				如ESP8266的返回格式为	"+IPD,x:yyy"	x代表数据长度,yyy是数据内容
//==========================================================
unsigned char* ESP8266_GetIPD(unsigned short timeOut)
{
    char* ptrIPD = NULL;

    do
    {
        if (ESP8266_WaitRecive() == REV_OK) //如果接收完成
        {
            ptrIPD = strstr((char*)esp8266_buf, "IPD,"); //搜索“IPD”头
            if (ptrIPD == NULL) //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
            {
                //printf("\"IPD\" not found\r\n");
            }
            else
            {
                ptrIPD = strchr(ptrIPD, ':'); //找到':'
                if (ptrIPD != NULL)
                {
                    ptrIPD++;
                    return (unsigned char*)(ptrIPD);
                }
                else
                    return NULL;
            }
        }

        HAL_Delay(5);
    }
    while (timeOut--);

    return NULL; //超时还未找到,返回空指针
}

unsigned char* ESP8266_GetIPD_soft(unsigned short timeOut)
{
    char* ptrIPD = NULL;

    do
    {
        if (ESP8266_WaitRecive() == REV_OK) //如果接收完成
        {
            ptrIPD = strstr((char*)esp8266_buf, "IPD,"); //搜索“IPD”头
            if (ptrIPD == NULL) //如果没找到,可能是IPD头的延迟,还是需要等待一会,但不会超过设定的时间
            {
                //printf("\"IPD\" not found\r\n");
            }
            else
            {
                ptrIPD = strchr(ptrIPD, ':'); //找到':'
                if (ptrIPD != NULL)
                {
                    ptrIPD++;
                    return (unsigned char*)(ptrIPD);
                }
                else
                    return NULL;
            }
        }

        osDelay(5);
    }
    while (timeOut--);

    return NULL; //超时还未找到,返回空指针
}

void ESP8266_Init(const int isSmartConfig)
{
    ESP8266_Clear();

    // reset ESP8266
    while (ESP8266_SendCmd("AT+RST\r\n", "ready")) HAL_Delay(500);
    // make sure ESP is up
    while (ESP8266_SendCmd("AT\r\n", "OK")) HAL_Delay(500);
    // set auto connect to AP
    while (ESP8266_SendCmd("AT+CWAUTOCONN=1\r\n", "OK")) HAL_Delay(500);
    // set CWMODE
    while (ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK")) HAL_Delay(500);

    if (isSmartConfig)
    {
        ESP8266_SmartConfig();
    }
    else
    {
        // connect to built-in AP
        // while (ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP")) HAL_Delay(1000);
        // wait until WiFi is up
        while (ESP8266_SendCmd("AT\r\n", "GOT IP")) HAL_Delay(1000);
    }
    // connect to OneNet via TCP
    while (ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT")) HAL_Delay(1000);
}

void ESP8266_SmartConfig(void)
{
    // start smart config
    while (ESP8266_SendCmd("AT+CWSTARTSMART=1\r\n", "OK")) HAL_Delay(500);
    // wait for smart config to finish
    while (ESP8266_SendCmd("AT\r\n", "smartconfig connected wifi")) HAL_Delay(500);
    // stop smart config
    while (ESP8266_SendCmd("AT+CWSTOPSMART\r\n", "OK")) HAL_Delay(500);
}

//==========================================================
//	函数名称:	ESP8266_IRQHandler
//
//	函数功能:	串口2收发中断
//
//	入口参数:	无
//
//	返回参数:	无
//

//	说明:
//==========================================================
//void ESP8266_IRQHandler(void)
//{
//		if(esp8266_cnt >= sizeof(esp8266_buf))
//    {
//       esp8266_cnt = 0; //防止串口被刷爆
//    }
//    esp8266_buf[esp8266_cnt++] = USART1->DR;
//}