#include "ec800.h"
#include "delay.h"
#include "string.h"
#include <stdlib.h>
#include "fmc.h"
#include "main.h"
/*!
    \brief      configure EC800M pin
    \param[out] none 
    \retval     none
*/
#define RSP_READY "RDY"
#define CMD_SET_PDP "AT+QICSGP=1,1,\"CTNET\",\"\",\"\",1\r\n" 
#define RSP_OK "OK"
#define CMD_SET_ACTIVE "AT+QIACT=1\r\n"

#define cmdOpenFile(cmd,filename) sprintf(cmd,"AT+QFOPEN=\"%s\",2\r\n",filename)
#define cmdSetSeek(cmd,handle,offset) sprintf(cmd,"AT+QFSEEK=%d,%d,0\r\n",handle,offset)
#define cmdReadFileData(cmd,handle) sprintf(cmd,"AT+QFREAD=%d,1024\r\n",handle)
#define cmdLoadFile(cmd,filename) sprintf(cmd,"AT+QFDWL=%s\r\n",filename)

uint8_t UART0_RX_BUF[UART0_RX_LEN];
uint8_t UART0_RX_STAT;
bool WaitResponse(char *expectStr, int timeout);
void EC800MSendCmd(char *buf, uint16_t len);
int get_file_handle(char *filename);
static const char* my_memmem(const uint8_t* haystack, size_t hlen, const char* needle, size_t nlen);
static void extract_data_from_buffer(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr);
static uint16_t checksum(const uint8_t *str, uint16_t len);

void gd_EC800M_pin_init(void)
{
    /* enable the EC800M power pin clock */
    rcu_periph_clock_enable(EC800M_PER_GPIO_CLK);
    /* configure EC800M GPIO port */ 
    gpio_init(EC800M_PER_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, EC800M_PER_PIN);

    GPIO_BC(EC800M_PER_GPIO_PORT) = EC800M_PER_PIN;

    /* enable the EC800M reset pin clock */
    rcu_periph_clock_enable(EC800M_RST_GPIO_CLK);
    /* configure EC800M GPIO port */ 
    gpio_init(EC800M_RST_GPIO_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, EC800M_RST_PIN);

    GPIO_BC(EC800M_RST_GPIO_PORT) = EC800M_RST_PIN;
    
}

void gd_pull_EC800M_pwr_up(void)
{
	GPIO_BOP(EC800M_PER_GPIO_PORT) = EC800M_PER_PIN;
}

void gd_pull_EC800M_pwr_down(void)
{
	GPIO_BC(EC800M_PER_GPIO_PORT) = EC800M_PER_PIN;
}

void gd_pull_EC800M_rst_up(void)
{
	GPIO_BOP(EC800M_RST_GPIO_PORT) = EC800M_RST_PIN;
}

void gd_pull_EC800M_rst_down(void)
{
	GPIO_BC(EC800M_RST_GPIO_PORT) = EC800M_RST_PIN;
}

/*!
    \brief      configure COM port
    \param[in]  com: COM on the board
        \arg        COM_EC800:   EC800
        \arg        COM_485: 485
	    \arg        COM_232: 232
    \param[out] none
    \retval     none
*/
void gd_com_init()
{
	  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);  // 设置抢占优先级和子优先级的位数为 2
		nvic_irq_enable(USART0_IRQn, 0, 0);
	
    /* enable GPIO clock */
    rcu_periph_clock_enable(COM_EC800_GPIO_CLK);
    /* enable USART clock */
    rcu_periph_clock_enable(COM_EC800_CLK);
    /* connect port to USARTx_Tx */
    gpio_init(COM_EC800_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_EC800_TX_PIN);
    /* connect port to USARTx_Rx */
    gpio_init(COM_EC800_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_EC800_RX_PIN);
		
    /* USART configure */
    usart_deinit(COM_EC800);
    usart_baudrate_set(COM_EC800, COM_EC800_BAUDRATE);
    usart_word_length_set(COM_EC800, USART_WL_8BIT);
    usart_stop_bit_set(COM_EC800, USART_STB_1BIT);
    usart_parity_config(COM_EC800, USART_PM_NONE);
    usart_hardware_flow_rts_config(COM_EC800, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(COM_EC800, USART_CTS_DISABLE);
    usart_receive_config(COM_EC800, USART_RECEIVE_ENABLE);
    usart_transmit_config(COM_EC800, USART_TRANSMIT_ENABLE);
    usart_enable(COM_EC800);
   	usart_interrupt_enable(COM_EC800, USART_INT_IDLE);
    
}
void dma_config(void)
{
    dma_parameter_struct dma_init_struct;

    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;		
    dma_init_struct.memory_addr = (uint32_t)UART0_RX_BUF;		
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;	
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;		
    dma_init_struct.number = UART0_RX_LEN;						
    dma_init_struct.periph_addr = (uint32_t)(&USART_DATA(USART0));// ((uint32_t)0x40013804);		
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;	
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;	
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;			
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
    
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);

    usart_dma_transmit_config(USART0, USART_DENT_ENABLE|USART_DENR_ENABLE);
		nvic_irq_enable(DMA0_Channel4_IRQn, 2, 1);
	
    dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF|DMA_INT_HTF|DMA_INT_ERR);
    dma_channel_enable(DMA0, DMA_CH4);
}

// 4G模块
void USART0_IRQHandler(void)
{
    if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) // 空闲中断
    {
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE); /* 清除空闲中断标志位 */
        usart_data_receive(USART0);                              /* 清除接收完成标志位 */
        dma_channel_disable(DMA0, DMA_CH4);                      /* 关闭DMA传输 */
        UART0_RX_STAT = 0x01;              /* 接受状态 0x01:已接收到数据 */
			  dma_channel_enable(DMA0, DMA_CH4);
			  
    }
}
void DMA0_Channel4_IRQHandler(void)
{
	dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
}

//清除dma buffer内数据
void Clear_DMA_Buffer(void)
{
   memset(UART0_RX_BUF,0,UART0_RX_LEN);
}
void EC800MPwoerOn(void)
{
	rcu_periph_clock_enable(RCU_GPIOD);
	gpio_init(GPIOD, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
	gpio_bit_set(GPIOD,GPIO_PIN_2);
	Delay_Ms(5000);
	gd_pull_EC800M_pwr_up();
	gd_pull_EC800M_rst_down();
	Delay_Ms(50);
	gd_pull_EC800M_pwr_down();
	Delay_Ms(320);
	gd_pull_EC800M_rst_up();
	Delay_Ms(800);
	gd_pull_EC800M_pwr_up();
}

void EC800MWaitReady()
{
	if(WaitResponse(RSP_READY, 5000)==FALSE) NVIC_SystemReset();
}

/*
 *  函数名：bool WaitResponse(char *expectStr, int timeout)
 *  输入参数：expectStr 需要匹配的关键字 timeout超时时间
 *  输出参数：true flase
 *  返回值：无
 *  函数作用：从UART0_RX_BUF缓冲区中匹配有无对应关键字有关键字则返回true无返回false
 */
bool WaitResponse(char *expectStr, int timeout)
{
	bool timeoutFlag = FALSE;
	if (timeout >= 0)
	{
		timeoutFlag = TRUE;
	}
	// gd_485_send((char *)&UART0_RX_BUF, strlen(UART0_RX_BUF)); 不清楚此处调用485意义

	while (1)
	{
		Delay_Ms(50);
		if (UART0_RX_STAT > 0)
		{
			UART0_RX_STAT = 0;
			char *p = strstr((char *)&UART0_RX_BUF, expectStr);
			if (p)
			{
				Clear_DMA_Buffer();
				return TRUE;
			}
		}
		timeout -= 50;
		if (timeoutFlag == TRUE && timeout <= 0)
		{
			Clear_DMA_Buffer();
			return FALSE;
		}
	};
}
/*
 *  函数名：bool WaitResponse(char *expectStr, int timeout)
 *  输入参数：expectStr 需要匹配的关键字 timeout超时时间
 *  输出参数：true flase
 *  返回值：无
 *  函数作用：从UART0_RX_BUF缓冲区中匹配有无对应关键字有关键字则返回true无返回false
 */
bool WaitResponseNotclear(char *expectStr, int timeout)
{
	bool timeoutFlag = FALSE;
	if (timeout >= 0)
	{
		timeoutFlag = TRUE;
	}
	// gd_485_send((char *)&UART0_RX_BUF, strlen(UART0_RX_BUF)); 不清楚此处调用485意义

	while (1)
	{
		Delay_Ms(50);
		if (UART0_RX_STAT > 0)
		{
			UART0_RX_STAT = 0;
			char *p = strstr((char *)&UART0_RX_BUF, expectStr);
			if (p)
			{
				return TRUE;
			}
		}
		timeout -= 50;
		if (timeoutFlag == TRUE && timeout <= 0)
		{
			return FALSE;
		}
	};
}
/*
 *  函数名：void EC800MSetPDP()
 *  输入参数：无
 *  输出参数：无
 *  返回值：无
 *  函数作用：设置对应运营商和激活ip
 */
void EC800MSetPDP()
{
	Delay_Ms(200);
	EC800MSendCmd(CMD_SET_PDP, strlen(CMD_SET_PDP));
	WaitResponse(RSP_OK, 1000);
	Delay_Ms(200);
	EC800MSendCmd(CMD_SET_ACTIVE, strlen(CMD_SET_ACTIVE));
	WaitResponse(RSP_OK, 1000);
	Delay_Ms(2000);
}

void EC800MSendCmd(char *buf, uint16_t len)
{
	uint16_t i;
	uint16_t data;
	for (i = 0; i < len; i++)
	{
		data = buf[i];
		usart_data_transmit(COM_EC800, data);
		while (RESET == usart_flag_get(COM_EC800, USART_FLAG_TBE))
			;
	}
}

//读取bin文件内容
int read_bin_txt()
{
	char *ptr;
	uint32_t len;
  uint16_t checkCode;
	char sub_str[] = "\r\n+QFDWL:";
	char cmd[50];
	uint32_t BufferSize=40*1024;//最大获取的数据空间
	uint8_t *dmabuffer=malloc(BufferSize);
	dma_config_change(dmabuffer,BufferSize);
	cmdLoadFile(cmd,"bin.txt");
//	Delay_Ms(1000);
//	EC800MSendCmd("AT+QFLST=\"*\"\r\n", strlen("AT+QFLST=\"*\"\r\n"));
	
	Delay_Ms(1000);
	EC800MSendCmd(cmd, strlen(cmd));
	Delay_Ms(5000);
	
	
	
	ptr = (char *)my_memmem(dmabuffer, BufferSize, sub_str, strlen(sub_str));
	if(ptr==NULL){	free(dmabuffer);return 2;}
	if(strstr(ptr,"ERROR"))
	{
		return 2;
	}
	extract_data_from_buffer(ptr,&len, &checkCode);
		uint16_t code=checksum(dmabuffer,len);
	if(checkCode==checksum(dmabuffer,len))
	{
		//校验成功数据正常,写入数据
			GD32_EraseFlash(GD32_A_START_PAGE,GD32_A_PAGE_NUM);//擦除A区原有程序
			GD32_WriteFlash(GD32_A_SADDR,(uint32_t *)dmabuffer,len);
			free(dmabuffer);
		return 1;
	}
	
  dma_config();
	free(dmabuffer);
	return 0;
}
////获取文件句柄
//int get_file_handle(char *filename)
//{
//	int num;
//	char *ptr_start;
//	ptr_start=strstr((char *)&UART0_RX_BUF, filename);
//	if (ptr_start == NULL) {}
//		ptr_start = strchr(ptr_start, ':');
//	 ptr_start++; // 跳过逗号
//	 sscanf(ptr_start, "%d", &num);
//	 return num;
//}


//手动控制dma搬运的数据地址和大小，在使用完成后需要恢复到默认的dma配置
void dma_config_change(char *dmaBuffer,uint32_t bufferSize)
{
	  dma_parameter_struct dma_init_struct;

    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;		
    dma_init_struct.memory_addr = (uint32_t)dmaBuffer;		
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;	
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;		
    dma_init_struct.number = bufferSize;						
    dma_init_struct.periph_addr = (uint32_t)(&USART_DATA(USART0));// ((uint32_t)0x40013804);		
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;	
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;	
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;			
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
    
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);

    usart_dma_transmit_config(USART0, USART_DENT_ENABLE|USART_DENR_ENABLE);
		//nvic_irq_enable(DMA0_Channel4_IRQn, 2, 2);
	
    dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF|DMA_INT_ERR);
    dma_channel_enable(DMA0, DMA_CH4);
}

static const char* my_memmem(const uint8_t* haystack, size_t hlen, const char* needle, size_t nlen)
{
	const char* cur;
	const char* last;

	last =  haystack + hlen - nlen;
	for (cur = haystack; cur <= last; ++cur) {
		if (cur[0] == needle[0] && memcmp(cur, needle, nlen) == 0) {
			return cur;
		}
	}
	return NULL;
}
/*
 *  函数名：static void extract_data_from_buffer(const char* buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr)
 *  输入参数：buffer字符串
 *  输出参数：json有效字符串长度len_ptr,checkCode_ptr校验码指针
 *  返回值：无
 *  函数作用:eg.   QFDWL: 621,3e23  从json信息最后端取出这段json的有效长度和校验码
 */
static void extract_data_from_buffer(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr)
{
  char *start = strstr(buffer, "+QFDWL:");
  if (start != NULL)
  {
    start += 8; // 跳过"+QFDWL:"
    uint32_t len = 0;
    sscanf(start, "%u,", &len);     // 读取长度
    start = strchr(start, ',') + 1; // 跳过逗号
    uint16_t checkCode = 0;
    sscanf(start, "%hx", &checkCode); // 读取16进制数据
    // 将提取的数据存入形参
    *len_ptr = len;
    *checkCode_ptr = checkCode;
  }
}
// 模块下载download校验值
static uint16_t checksum(const uint8_t *str, uint16_t len)
{
  uint16_t sum = 0;
  uint8_t odd = 0;

  // 如果字符串长度为奇数，则将最后一个字符设置为高8位，低8位设置为0
  if (len % 2 == 1)
  {
    odd = 1;
    len--;
  }

  // 将每两个字符作为一个16位的数值进行异或操作
  for (uint16_t i = 0; i < len; i += 2)
  {
    sum ^= ((uint16_t)str[i] << 8) | (uint16_t)str[i + 1];
  }

  // 如果字符串长度为奇数，则还需要将最后一个字符与0xFF00异或
  if (odd)
  {
    sum ^= (uint16_t)str[len] << 8;
  }
  // 返回校验和
  return sum;
}

