/*!
	\file    main.c
	\brief   led spark with systick, USART print and key example

	\version 2014-12-26, V1.0.0, firmware for GD32F10x
	\version 2017-06-20, V2.0.0, firmware for GD32F10x
	\version 2018-07-31, V2.1.0, firmware for GD32F10x
	\version 2020-09-30, V2.2.0, firmware for GD32F10x
*/

/*
	Copyright (c) 2020, GigaDevice Semiconductor Inc.

	Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

	1. Redistributions of source code must retain the above copyright notice, this
	   list of conditions and the following disclaimer.
	2. Redistributions in binary form must reproduce the above copyright notice,
	   this list of conditions and the following disclaimer in the documentation
	   and/or other materials provided with the distribution.
	3. Neither the name of the copyright holder nor the names of its contributors
	   may be used to endorse or promote products derived from this software without
	   specific prior written permission.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "gd32f10x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "usart.h"
#include "led.h"
#include "config.h"
#include "log.h"
#include "ec800m.h"
#include "parseDeviceMessage.h"

#include "otaEvent.h"

#include "systick.h"
#include "w25q32.h"
#include "key.h"
#define UNIQUE_ID 0x1FFFF7E8


#define VERSION "V1.0.0" // 版本号写死、通过人工手动控制
#define GATEWAYNAME "DTU"
#define GATEWAYMODE "4G" // 后续此mode可以切换4g


void MQTT_Alarm_clock(uint32_t time, CONFIG_PARAMS *gateway);
void readID(char *strId);
void http_load_config(uint8_t *httpURL);
void fwdgt_init();
void task_fwdgt_reload();

uint8_t protocol;

int main(void)
 {
	/* configure systick */
	rcu_osci_on(RCU_HXTAL);
	systick_config();
	nvic_config();
	/* initilize the LEDs, USART */
	W25Q32_Init();
	gd_eval_led_init(LED1);
	gd_com_init(COM_232);
	gd_com_init(COM_EC800);
	dma_config();
	gd_EC800M_pin_init();
	gd_eval_key_init(KEY_SYS_RECOVERY, KEY_MODE_EXTI);
	EC800MPwoerOn();
	EC800MWaitReady();
	EC800MSetPDP();
	
	char *strID = malloc(24);
	
	readID(strID);
	//加载网关信息
	CONFIG_PARAMS *gateway;
	gateway = get_config_params();
	
	strcpy(gateway->deviceId, strID);
	strcpy(gateway->version, VERSION);
	strcpy(gateway->gatewayMode, GATEWAYMODE);
	strcpy(gateway->gateName,GATEWAYNAME);
	
	
	char *httpURL = malloc(100);
	memset(httpURL, 0, 100);
	sprintf(httpURL, "http://gpu.ringzle.com:8082/iot/transmit/getTransmitConfig?deviceId=%s",strID);
 	http_load_config(httpURL);
	free(httpURL);
	
	
	if (load_config_params() == -1)
	{
		check_ota_event();
		strcpy(gateway->deviceId, strID);
		strcpy(gateway->version, VERSION);
		strcpy(gateway->gatewayMode, GATEWAYMODE);
		strcpy(gateway->gateName,GATEWAYNAME);
		LogPrint(LOG_ERROR, __func__, __LINE__, "No information in flash");
		while (1) // flash中不含信息则会等待看门狗
			;
	}
	//跳出获取信息循环后重新加载一下网关配置
	gateway = get_config_params();
	strcpy(gateway->version, VERSION);
	strcpy(gateway->gatewayMode, GATEWAYMODE);
	strcpy(gateway->gateName,GATEWAYNAME);
	
	free(strID);
	protocol = gateway->dataSource;
	config_485_port(COM_485, gateway->baudrate, gateway->dataBits, gateway->stopBit, gateway->checkBit, gateway->flowControl);
	gd_485_DE_pin_init();
	gd_485_DE_tx();
	ConnectMQTTSever(gateway->host, gateway->port, 60, gateway->deviceId);
	MQTTSubTopic(gateway->commandTopic);

	ring_buffer_init(&mqttRecv);

	switch (gateway->dataSource)
	{
		case MODBUS:
			mmodbus_init(1);
			break;
		case DLT645:
			dlt645_init(1);
			break;
		default:
			LogPrint(LOG_ERROR, __func__, __LINE__, "protocol modbus is 2,dlt645 is 1 ;please check protocol setting");
			break;
	}
	while (1)
	{
		//开启看门狗
		fwdgt_init();
		check_ota_event();                              //检测是否有ota事件产生
		MQTT_Alarm_clock(gateway->inboundTime, gateway);
	}
}
/*
 *  函数名：void MQTT_Alarm_clock(uint32_t time)
 *  输入参数：time设定MQTT多久进行一次上传
 *  输出参数：无
 *  返回值：无
 *  函数作用：按照设定好时间进行执行，在未到达指定时间之前重复做led反转、MQTT订阅的主题是否有下发主题信息判断
 * 	当time为0时进行数据采集和数据上传
 */
void MQTT_Alarm_clock(uint32_t time, CONFIG_PARAMS *gateway)
{
	while (1)
	{
		if (time <= 0)
		{
			switch (gateway->dataSource)
			{
			case MODBUS:
				modbusRead(gateway);
				break;
			case DLT645:
				dlt645_read(gateway);
				break;
			}
			MQTTPublish(gateway);
			break; // 跳出while循环
		}
		else
		{
			gd_eval_led_toggle(LED1);
			parseMQTTData(gateway);
			check_ota_event();
		}
		delay_1ms(1000);
		time-=1000; 
		task_fwdgt_reload();
	}
}

/*
 *  函数名：void readID(char *strId)
 *  输入参数：无
 *  输出参数：strId
 *  返回值：无
 *  函数作用：读取长度12的芯片Id并组合从中取出对应字符防止其重复
 */
void readID(char *strId)
{
	static const char *hex_table = "0123456789abcdefghijklmnopqrstuvwxyzzABCDEFGHIJKLMN";
	uint32_t CpuID1, CpuID2, CpuID3;
	CpuID1 = *(volatile uint32_t *)(0x1FFFF7E8);
	CpuID2 = *(volatile uint32_t *)(0x1FFFF7EC);
	CpuID3 = *(volatile uint32_t *)(0x1FFFF7F0);
	strId[0] = 'D';
	strId[1] = 'T';

	for (uint8_t i = 0, j = 0; i < 8; i += 2)
	{
		uint32_t sum1 = (CpuID1 >> ((j % 4) * 8)) & 0xFF; // 按字节取出
		uint8_t index1 = sum1 / 16;
		uint8_t remainder1 = sum1 % 16;

		uint32_t sum2 = (CpuID2 >> ((j % 4) * 8)) & 0xFF; // 按字节取出
		uint8_t index2 = sum2 / 16;
		uint8_t remainder2 = sum2 % 16;

		uint32_t sum3 = (CpuID3 >> ((j % 4) * 8)) & 0xFF; // 按字节取出
		uint8_t index3 = sum3 / 16;
		uint8_t remainder3 = sum3 % 16;

		strId[i + 2] = hex_table[index1 + index2 + index3];
		strId[i + 1 + 2] = hex_table[remainder1 + remainder2 + remainder3];

		j++;
	}
	strId[10] = '\0';
}

/*
 *  函数名：void http_load_config(uint8_t *httpURL)
 *  输入参数：httpURL 获取参数配置的网址
 *  输出参数：strId
 *  返回值：无
 *  函数作用：拉取http配置
 */
void http_load_config(uint8_t *httpURL)
{
	if (EC800MGetUrl(httpURL) == true) // 从http获取信息，获取成功则保存到本地
	{
		WaitForUpData();
	}
	else
	{
		LogPrint(LOG_INFO, __func__, __LINE__, "Http failed to obtain information");
	}
}
/*
 *  函数名：void fwdgt_init(void)
 *  输入参数：无
 *  输出参数：无
 *  返回值：无
 *  函数作用：初始化硬件看门狗
 */
void fwdgt_init(void)
{
	rcu_osci_on(RCU_IRC40K); // IRC40K时钟打开
	/* confiure FWDGT counter clock: 40KHz(IRC40K) / 256= 0.015625 KHz */
	fwdgt_config(0x0FFF, FWDGT_PSC_DIV256); // 看门狗时间设置
	fwdgt_enable();							// 看门狗使能
}
void task_fwdgt_reload(void)
{
	/* uncock fwdgt write protect*/
	fwdgt_write_enable();
	/* feed fwdgt */
	fwdgt_counter_reload();	
}
#if 0 // 本地信息调试使用
	gateway->dataSource=MODBUS;
	gateway->baudrate=9600;
	gateway->dataBits=8;
	gateway->stopBit=1;

	gateway->checkBit=0;
	gateway->flowControl=0;
	gateway->device_read_data_num=1;
	
	gateway->device_read_data[0].deviceID645[0]=0x20;
	gateway->device_read_data[0].deviceID645[1]=0x92;
	gateway->device_read_data[0].deviceID645[2]=0x20;
	gateway->device_read_data[0].deviceID645[3]=0x00;
	gateway->device_read_data[0].deviceID645[4]=0x73;
	gateway->device_read_data[0].deviceID645[5]=0x81;
	
	gateway->device_read_data[0].dataType645=0x01010000;

	gateway->device_read_data[0].mdbSlave=0x17;
	gateway->device_read_data[0].mdbFunctionCode=0x03;
	gateway->device_read_data[0].mdbRegister=0x0000;
	gateway->device_read_data[0].registerLength=2;
#endif
