#include "parseDeviceMessage.h"
#include "cJson.h"
#include "systick.h"
#include "usart.h"
#include "string.h"
#include <math.h>
#include "mqttRecv.h"
#include "log.h"
#include "ec800m.h"
#include "main.h"

#define MQTT_SUB_CMD_WRITE 0
#define MQTT_SUB_CMD_READ 1
ring_buffer mqttRecv;
uint8_t protocol;
void processHTTPjson(cJSON *json);
char *processStringData(cJSON *data_obj, const char *key);
int processIntData(cJSON *data_obj, const char *key);


static void extract_data_from_buffer(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr);
//static void extract_data_from_buffer232(const char *buffer, uint32_t *len_ptr, uint16_t *checkCode_ptr);
static uint16_t checksum(const char *str, uint16_t len);

// json解析字符串
char *processStringData(cJSON *data_obj, const char *key)
{
  cJSON *json_data = cJSON_GetObjectItemCaseSensitive(data_obj, key);
  if (cJSON_IsString(json_data) && (json_data->valuestring != NULL))
  {
    return json_data->valuestring;
  }
  else
  {
    return NULL;
  }
}
// json解析int
int processIntData(cJSON *data_obj, const char *key)
{
  cJSON *json_data = cJSON_GetObjectItemCaseSensitive(data_obj, key);
  // if (cJSON_IsNumber(json_data) && (json_data->valueint != NULL)) 解决寄存器地址为0问题
  if (cJSON_IsNumber(json_data))
  {
    return json_data->valueint;
  }
  else
  {
    // gateway.data_valid_flag = 0; // 如果任意数据为NULL则此次数据为无效
    return -1;
  }
}



/*
 *  函数名：void WaitForUpData(void)
 *  输入参数：无
 *  输出参数：无
 *  返回值：无
 *  函数作用:等待更新本地flash信息
 */

bool WaitForUpData(char *dmaBuffer)
{
	if (UART0_RX_STAT > 0)
  {
    UART0_RX_STAT = 0;
    uint32_t len;
    uint16_t checkCode;
		char *temp;
    extract_data_from_buffer(dmaBuffer, &len, &checkCode);
    uint16_t jsonCheck = checksum(dmaBuffer, len);
    if (checkCode == jsonCheck)
    {
				addGatewayParams(dmaBuffer);
				return true;
		}
		else
		{
			return false;
		}
  }
}





/*
 *  函数名：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;
  }
}







/*
 *  函数名：void dlt645_read(CONFIG_PARAMS *gateway)
 *  输入参数：设备地址*address 数据标识 readCode
 *  输出参数：无
 *  返回值：无
 *  函数作用：读取645协议内部数据
备注：dlt645协议为网上下载，返回值为数据长度
      现在要加读日期信息YYMMDDhhmm
      对源代码改动不多的方法是通过返回的数据长度去做判断
      当数据长度为2、3、4时此时 read_buf数据包内仅含采集到的浮点数数据、          把float值4个字节直接拷贝出即可
      当数据长度为5时           read_buf数据包为日期数据                          其中5个字节分别为YYMMDDhhmm直接拷贝出来
      当数据长度大于5时         read_buf内既包含浮点数又包含日期时间              其中前4个字节为浮点数数据后五个字节为日期信息
*/

#if 0
void dlt645_read(CONFIG_PARAMS *gateway)
{
  uint8_t read_buf[10];
  for (int i = 0; i < gateway->device_read_data_num; i++)
  {
    gateway->device_read_data[i].rxLen = 0;
    
    memset(read_buf, 0, 10);
    memset(gateway->device_read_data[i].data, 0, 10); 
    dlt645_set_addr(&dlt645, gateway->device_read_data[i].deviceID645);
		int8_t rs;
		if(gateway->dataType645==DLT645_2007){
			rs = dlt645_read_data(&dlt645, gateway->device_read_data[i].dataType645, read_buf, DLT645_2007);
		}
		else {
			rs = dlt645_read_data(&dlt645, gateway->device_read_data[i].dataType645, read_buf, DLT645_1997);
		}
    if (rs != -1)
    {
      if (rs <= 4)
      {
        memcpy(gateway->device_read_data[i].data, read_buf, 4);
        gateway->device_read_data[i].rxLen = rs;
      }
      else if (rs == 5)
      {
        memcpy(gateway->device_read_data[i].data, read_buf, 5);
        gateway->device_read_data[i].rxLen = rs;
      }
      else if (rs > 5)
      {
        memcpy(gateway->device_read_data[i].data, read_buf, 9);
        gateway->device_read_data[i].rxLen = rs;
      }
    }
    else
    {
      gateway->device_read_data[i].rxLen = 0;
    }
		task_fwdgt_reload();
		}
  
}
#endif
/*
 *  函数名： void Read_Data(GATEWAY_PARAMS *gateway)
 *  输入参数：gateway网关存储的配置参数
 *  输出参数：网关结构体指针
 *  返回值：无
 *  函数作用:根据存储的设备信息发送modbus信息返回值存储到gateway->device_read_data[i].data中
 *           modbusRead读数据只考虑读16位寄存器和32位寄存器这两种情况，但对其返回值进行处理后返回值一律为float型4个字节存储在内部
						 dlt645根据其返回长度判断其具体是否挈带了日期数据
 */
void Read_Data()
{
	GATEWAY_PARAMS *gateway;
	gateway=get_gateway_config_params();
	DEVICE_PARAMS *currentDevice=gateway->device_params;
	READ_MODBUS_COMMAND *read_modbus_command=NULL;
	READ_DLT645_COMMAND *read_dlt645_command=NULL;
	switch(currentDevice->protocol)
	{
		case DLT645_07:
		case DLT645_97:
			protocol=1;
			read_dlt645_command=currentDevice->params->node_read_dlt645_command;
		break;
		case MODBUS:
			protocol=2;
			read_modbus_command=currentDevice->params->node_read_modbus_command;
			mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat);               //设置大小端
		break;
	}
	
	while(1)//进入轮询
	{
__START__WHILE:
		delay_1ms(10);
		switch(currentDevice->protocol)
		{
		  case DLT645_07:
  		case DLT645_97:
			{
				 uint8_t read_buf[10];
				 memset(read_buf, 0, 10);
				 dlt645_set_addr(&dlt645,read_dlt645_command->deviceID645);
				 int8_t rs;
				 if(currentDevice->protocol==DLT645_97)
				 {
						rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_1997);					 
				 }
				 else if(currentDevice->protocol==DLT645_07)
				 {
						rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_2007);					 
				 }
				 if (rs != -1)
					{
						if (rs <= 4)
						{
							memcpy(read_dlt645_command->data, read_buf, 4);
							read_dlt645_command->rxLen = 4;
						}
						else if (rs == 5)
						{
							memcpy(read_dlt645_command->data, read_buf, 5);
							read_dlt645_command->rxLen = 5;
						}
						else if (rs > 5)
						{
							memcpy(read_dlt645_command->data, read_buf, 9);
							read_dlt645_command->rxLen = 9;
						}
					}
					else
					{
						read_dlt645_command->rxLen = 0;
					}
				 
			}	
				break;
			case MODBUS:
			{
				
				uint16_t data[read_modbus_command->registerByteNum/2];
				switch(read_modbus_command->functionCode)
				{
					case 0x03://读寄存器
						{
							bool success=mmodbus_readHoldingRegisters16i(read_modbus_command->slaveAddress,
																													 read_modbus_command->registerAddress,
																													 read_modbus_command->registerByteNum/2,
																													 data);
							if(success)
							{
								uint32_t value;
								if(read_modbus_command->registerByteNum==4)
								{
									 value = (uint32_t)data[0] << 16 | data[1];
									 read_modbus_command->rxLen=4;
								}
								else if(read_modbus_command->registerByteNum==2)
								{
									value = data[0];
									read_modbus_command->rxLen=4;
								}
								if(read_modbus_command->decimalPoint!=0)
								{
									float convertedValue =(float)value/pow(10,read_modbus_command->decimalPoint);
									memcpy(read_modbus_command->value,&convertedValue,4);
								}
								else
								{
									memcpy(read_modbus_command->value,&value,4);
								}
							}
							else
							{
								read_modbus_command->rxLen=0;
							}
						}
						break;
					case 0x01://读线圈
					{
						uint8_t data[2];
						bool success = mmodbus_readCoils(read_modbus_command->slaveAddress,
																													 read_modbus_command->registerAddress,
																													 read_modbus_command->registerByteNum/2,
																													 data);
						if(success)
						{
							read_modbus_command->rxLen=4;
							uint32_t value = (uint32_t)data[0] << 8 | data[1];
							memcpy(read_modbus_command->value,&value,4);
						}
						else
						{
							read_modbus_command->rxLen=0;
						}
						
					}
						break;
					default:
						break;
				}
			}
				break;
		}
		switch(currentDevice->protocol)
		{
		  case DLT645_07:
  		case DLT645_97:
				read_dlt645_command=read_dlt645_command->nextParams;
				break;
			case MODBUS:
				read_modbus_command=read_modbus_command->nextParams;
				break;
		}
		if((read_dlt645_command==NULL&&protocol==1)||(read_modbus_command==NULL&&protocol==2))
		{
			currentDevice=currentDevice->nextDevice;
			switch(currentDevice->protocol)
			{
				case DLT645_97:
				case DLT645_07:
					protocol=1;
				break;
				case MODBUS:
					protocol=2;
				break;
			}
			if(currentDevice==NULL)
			{
				return;//一直到没有设备时跳出循环
			}
			else
			{
				read_dlt645_command=currentDevice->params->node_read_dlt645_command;
				read_modbus_command=currentDevice->params->node_read_modbus_command;
			}
		}
		task_fwdgt_reload();//喂狗
		goto __START__WHILE; 
	}
}


/*
 *  函数名：void parseMQTTData(CONFIG_PARAMS *gateway)
 *  输入参数：device存储的各类产品信息
 *  输出参数：无
 *  返回值：无
 *  函数作用:从环形缓冲区中一个个把json信息读出，与存储的gateway内的子设备信息匹配后将对应指令匹配执行并返回相应的值
 *  查询逻辑现在有两套数组read数组和write数组，当接收中断产生时先判断是进行读还是写、之后在查询此网关支持的协议MODBUS还是
 *  645，后根据协议去不同数组查询不同的本地存储信息、组装发送给子设备,然后根据查询的值进行采集上传数据
 */
void parseMQTTData(GATEWAY_PARAMS *gateway)
{
  while (UART0_RX_MQTT_SUB_STAT == 1)
  {
    UART0_RX_MQTT_SUB_STAT = 0;
    char payload_out[200];
		memset(payload_out,0,200);
    char mqtt_publish[200];
    char json[128];
    while (MQTT_BUFFER_READ(json))
    {
      LogPrint(LOG_INFO, __func__, __LINE__, "Received JSON: %s", json);
      cJSON *mqtt_sub_json = cJSON_Parse(json);
      if (mqtt_sub_json != NULL)
      {
        uint8_t action1[1];
        uint8_t action;
        strcpy(action1, processStringData(mqtt_sub_json, "action"));
        // 解决字符串为
        if (action1[0] == '0')
        {
          action = 0;
        }
        else if (action1[0] == '1')
        {
          action = 1;
        }
        char identifier[20];
        strcpy(identifier, processStringData(mqtt_sub_json, "identifier"));
        char deviceId[20];
        strcpy(deviceId, processStringData(mqtt_sub_json, "deviceId"));
        uint16_t value = processIntData(mqtt_sub_json, "parameter");
        char messageId[10];
        strcpy(messageId, processStringData(mqtt_sub_json, "messageId"));
				
				
				DEVICE_PARAMS *currentDevice=gateway->device_params;
				WRITE_MODBUS_COMMAND *write_modbus_command=NULL;
				READ_MODBUS_COMMAND *read_modbus_command=NULL;
				READ_DLT645_COMMAND *read_dlt645_command=NULL;
        // 判断其指令过来是读还是写
        if (action == MQTT_SUB_CMD_WRITE)//写指令目前只支持modbus
        {
					while(1)
					{
						if(strcmp((char *)&currentDevice->deviceID,deviceId)!=0)
						{
							currentDevice=currentDevice->nextDevice;
							if(currentDevice==NULL)
							{
								break;  //如果找不到所属设备则跳出
							}
						}
						else
						{
							protocol=2;//决定当前使用modbus回调函数还是dlt645
							if(write_modbus_command==NULL)
							{
								write_modbus_command=currentDevice->params->node_write_modbus_command;
							}
							if(strcmp((char*)&write_modbus_command->keyword,identifier)!=0)//寻找设备层内所属属性名称
							{
								write_modbus_command=write_modbus_command->nextParams;
								if(write_modbus_command==NULL)
								{
									break;								
								}
							}
							else //找到所属于的属性了
							{
								mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat);
								if(write_modbus_command->functionCode==0x05)
								{
                    bool success = mmodbus_writeCoil(write_modbus_command->slaveAddress,
                                                     write_modbus_command->registerAddress,
                                                     (uint8_t)value);
                    // 成功
                    if (success)
                    {
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                              action1,
                              write_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success);
										break;
                    }
                    else
										{
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                              action1,
                              write_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success);
											break;
										}
								}
								else if(write_modbus_command->functionCode==0x06)
								{
                    bool success = mmodbus_writeHoldingRegister16i(write_modbus_command->slaveAddress,
                                                                   write_modbus_command->registerAddress,
                                                                   (uint16_t)value);
                    if (success)
                    {
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                              action1,
                              write_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success);
											break;
                    }
                    else
										{
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                              action1,
                              write_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success);
											break;
										}									
								}
							}
						}
					}
        }
        // 指令是来读某属性值的
        else if (action == MQTT_SUB_CMD_READ)
        {
					while(1)
					{
						if(strcmp((char *)&currentDevice->deviceID,deviceId)!=0)
						{
							currentDevice=currentDevice->nextDevice;
							if(currentDevice==NULL)
							{
								break;  //如果找不到所属设备则跳出
							}
						}
						else //找到了设备
						{
							if(currentDevice->protocol==MODBUS)
							{
								protocol=2;//决定当前使用modbus=2回调函数还是dlt645=1
								if(read_modbus_command==NULL)read_modbus_command=currentDevice->params->node_read_modbus_command;
								if(strcmp((char *)&read_modbus_command->keyword,identifier)!=0)
								{
									read_modbus_command=read_modbus_command->nextParams;
									if(read_modbus_command==NULL)break;
								}
								else//找到了属性
								{
									mmodbus_set16bitOrder(currentDevice->MDBbigLittleFormat);
									if(read_modbus_command->functionCode==0x01)
									{
										uint8_t data[2];
                    bool success = mmodbus_readCoils(read_modbus_command->slaveAddress,
                                                     read_modbus_command->registerAddress,
                                                     read_modbus_command->registerByteNum/2,
                                                     data);
                    uint8_t value1;
                    if (success)
                    {
                      uint16_t value1 = (uint16_t)data[0] << 8 | data[1];
                      if (value1 == 0xFF00)
                      {
                        value1 = 1;
                      }
                      else if (value1 == 0x0000)
                      {
                        value1 = 0;
                      }
                      // 读线圈成功的json
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"parameter\":%d}",
                              action1,
                              read_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success, value);
											break;
                    }
                    // 读线圈失败的json
                    else
										{
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                              action1,
                              read_modbus_command->keyword,
                              currentDevice->deviceID, messageId, success);
											break;
										}										
									}
								}
							}
							else//dlt645读取指令
							{
									protocol=1;//决定当前使用modbus=2回调函数还是dlt645=1
									float value;
                  uint8_t minute, hour, day, month, year;
                  uint8_t read_buf[10];
                  memset(read_buf, 0, 10);
									if(read_dlt645_command==NULL)read_dlt645_command=currentDevice->params->node_read_dlt645_command;
                  dlt645_set_addr(&dlt645, read_dlt645_command->deviceID645);
									int8_t rs ;
									if(currentDevice->protocol==DLT645_07)
									{
										rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_2007);
									}else if(currentDevice->protocol==DLT645_97)
									{
										rs = dlt645_read_data(&dlt645, read_dlt645_command->Identification, read_buf, DLT645_1997);
									}
                  if (rs != -1)
                  {
                    if (rs <= 4)
                    {
                      memcpy(&value, read_buf, 4);
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":%.2f}",
                              action1,
                              read_dlt645_command->keyword,
                              currentDevice->deviceID, messageId, 1, value);
											break;
                    }
                    else if (rs == 5)
                    {
                      year = read_buf[4];
                      month = read_buf[3];
                      day = read_buf[2];
                      hour = read_buf[1];
                      minute = read_buf[0];
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":\"%02X%02X%02X%02X%02X\"}",
                              action1,
                              read_dlt645_command->keyword,
                              currentDevice->deviceID, messageId, 1, year, month, day, hour, minute);
											break;
                    }
                    else if (rs > 5)
                    {
                      memcpy(&value, read_buf, 4);
                      year = read_buf[8];
                      month = read_buf[7];
                      day = read_buf[6];
                      hour = read_buf[5];
                      minute = read_buf[4];
                      sprintf((char *)payload_out,
                              "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d,\"value\":\"%02X%02X%02X%02X%02X%.2f\"}",
                              action1,
                              read_dlt645_command->keyword,
                              currentDevice->deviceID, messageId, 1, year, month, day, hour, minute, value);
											break;
                    }
                  }
                  else
                  {
                    // dlt645读取失败的json组成
                    sprintf((char *)payload_out,
                            "{\"action\":\"%s\",\"identifier\":\"%s\",\"deviceId\":\"%s\",\"messageId\":\"%s\",\"state\":%d}",
                            action1,
                            read_dlt645_command->keyword,
                            currentDevice->deviceID, messageId, 0);
										break;
                  }
							}
						}
					}
				}
        // 上传对应的响应信息
        sprintf((char *)mqtt_publish, "AT+QMTPUBEX=0,0,0,0,\"%s\",%d\r\n", gateway->messageTopic, strlen(payload_out));
        EC800MSendCmd(mqtt_publish, strlen(mqtt_publish));
        WaitResponse("<", 1000);
        EC800MSendCmd(payload_out, strlen(payload_out));
        WaitResponse(RSP_OK, 1000);
      }
      cJSON_Delete(mqtt_sub_json);
    }
  }
}


// 模块下载download校验值
static uint16_t checksum(const char *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;
}
//比较本次数据和上次数据是否相同如果相同则不进行数据的更新
int compareWithLastData(char *old_data,const char* new_data,uint8_t dataLen) {
    if (memcmp(new_data, old_data,dataLen) == 0) {
        return 0;
    } else {
        memcpy(old_data,&new_data,dataLen);;
        return 1;
    }
}
