zhao006 8 miesięcy temu
rodzic
commit
6326d7c0a5
50 zmienionych plików z 4315 dodań i 210 usunięć
  1. 2 2
      app/CMSIS/source/startup_gd32f30x_cl.s
  2. 11 0
      app/HW/include/delay.h
  3. 67 0
      app/HW/include/include.h
  4. 1 1
      app/HW/include/netconf.h
  5. 14 0
      app/HW/include/timer.h
  6. 64 0
      app/HW/source/delay.c
  7. 4 1
      app/HW/source/hd_eth.c
  8. 16 1
      app/HW/source/netconf.c
  9. 45 0
      app/HW/source/timer.c
  10. 29 16
      app/HW/source/usart.c
  11. BIN
      app/MDK/Objects/dtu_simple.axf
  12. 290 125
      app/MDK/dtu_simple.uvoptx
  13. 82 6
      app/MDK/dtu_simple.uvprojx
  14. 45 0
      app/System/include/data_task.h
  15. 145 0
      app/System/include/gateway_message.h
  16. 4 1
      app/System/include/gd32_flash.h
  17. 471 0
      app/System/include/jsmn.h
  18. 16 0
      app/System/include/protocol.h
  19. 11 0
      app/System/include/sys_http.h
  20. 5 2
      app/System/include/sys_mqtt.h
  21. 416 0
      app/System/source/data_task.c
  22. 317 0
      app/System/source/gateway_message.c
  23. 1 1
      app/System/source/gd32_flash.c
  24. 2 1
      app/System/source/httpclient.c
  25. 1 0
      app/System/source/log.c
  26. 48 0
      app/System/source/sys_http.c
  27. 37 9
      app/System/source/sys_mqtt.c
  28. 10 23
      app/System/source/tcp_server.c
  29. 1 1
      app/System/source/udp.c
  30. 3 3
      app/USR/include/FreeRTOSConfig.h
  31. 3 0
      app/USR/include/main.h
  32. 32 13
      app/USR/source/main.c
  33. 1 1
      app/USR/source/tcp_client.c
  34. 47 0
      app/dlt/inc/dlt645.h
  35. 11 0
      app/dlt/inc/dlt645_1997.h
  36. 53 0
      app/dlt/inc/dlt645_1997_private.h
  37. 11 0
      app/dlt/inc/dlt645_2007.h
  38. 128 0
      app/dlt/inc/dlt645_2007_private.h
  39. 56 0
      app/dlt/inc/dlt645_private.h
  40. 132 0
      app/dlt/port/dlt645_port.c
  41. 10 0
      app/dlt/port/dlt645_port.h
  42. 131 0
      app/dlt/src/dlt645.c
  43. 141 0
      app/dlt/src/dlt645_1997.c
  44. 279 0
      app/dlt/src/dlt645_2007.c
  45. 289 0
      app/dlt/src/dlt645_data.c
  46. 648 0
      app/modbus/mmodbus.c
  47. 164 0
      app/modbus/mmodbus.h
  48. 18 0
      app/modbus/mmodbusConfig.h
  49. 2 2
      app/mqttclient/mqttclient/mqttclient.c
  50. 1 1
      app/mqttclient/mqttclient/mqttclient.h

+ 2 - 2
app/CMSIS/source/startup_gd32f30x_cl.s

@@ -39,7 +39,7 @@
 ;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
 ; </h>
 
-Stack_Size      EQU     0x00000800
+Stack_Size      EQU     0x00001000
 
                 AREA    STACK, NOINIT, READWRITE, ALIGN=3
 Stack_Mem       SPACE   Stack_Size
@@ -50,7 +50,7 @@ __initial_sp
 ;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
 ; </h>
 
-Heap_Size       EQU     0x000000800
+Heap_Size       EQU     0x000001000
 
                 AREA    HEAP, NOINIT, READWRITE, ALIGN=3
 __heap_base

+ 11 - 0
app/HW/include/delay.h

@@ -0,0 +1,11 @@
+#ifndef __DELAY_H
+#define __DELAY_H
+#include "gd32f30x.h"
+#include "stdint.h"
+
+void delay_init(void);
+void delay_ms(uint16_t nms);
+void delay_us(uint32_t nus);
+
+#endif
+

+ 67 - 0
app/HW/include/include.h

@@ -0,0 +1,67 @@
+
+
+#ifndef  INCLUDES_PRESENT
+#define  INCLUDES_PRESENT
+
+#define  DATA_RAM(x)  __attribute__ ((section("x")));
+
+
+/*
+*********************************************************************************************************
+*                                         STANDARD LIBRARIES
+*********************************************************************************************************
+*/
+
+#include  <stdarg.h>
+#include  <stdio.h>
+#include  <stdlib.h>
+#include  <math.h>
+
+
+/*
+*********************************************************************************************************
+*                                              LIBRARIES
+*********************************************************************************************************
+*/
+
+
+
+
+/*
+*********************************************************************************************************
+*                                              APP / BSP
+*********************************************************************************************************
+*/
+#include "delay.h"
+
+
+
+/*
+*********************************************************************************************************
+*                                                 OS
+*********************************************************************************************************
+*/
+
+#include <FreeRTOS.h>
+
+
+/*
+*********************************************************************************************************
+*                                                 ST
+*********************************************************************************************************
+*/
+#include "gd32f30x.h"
+#include "gd32f30x_enet.h"
+#include "hd_eth.h"
+
+
+
+/*
+*********************************************************************************************************
+*                                            INCLUDES END
+*********************************************************************************************************
+*/
+
+
+#endif
+

+ 1 - 1
app/HW/include/netconf.h

@@ -17,5 +17,5 @@
 void lwip_stack_init(void);
 /* dhcp_task */
 void dhcp_task(void * pvParameters);
-
+extern volatile int dhcp_done;
 #endif /* NETCONF_H */

+ 14 - 0
app/HW/include/timer.h

@@ -0,0 +1,14 @@
+#ifndef  __TIMER_H  
+#define  __TIMER_H  
+
+//包含头文件 
+#include "gd32f30x.h"
+#include "delay.h"
+
+extern volatile uint32_t delay_counter; // 延时计数器
+
+extern void timer5_init(void);//初始化定时器4函数
+extern void timer5_start(void);//启动定时器4命令函数
+extern void timer5_stop(void);//关闭定时器4命令函数 
+
+#endif

+ 64 - 0
app/HW/source/delay.c

@@ -0,0 +1,64 @@
+#include "delay.h"
+#include "gd32f30x_misc.h"
+#include "timer.h"
+
+#define 	TIMER  1
+
+
+static uint8_t  fac_us=0;							//us延时倍乘数			   
+static uint16_t fac_ms=0;							//ms延时倍乘数,在ucos下,代表每个节拍的ms数
+		   
+//初始化延迟函数
+//当使用OS的时候,此函数会初始化OS的时钟节拍
+//SYSTICK的时钟固定为HCLK时钟的1/8
+//SYSCLK:系统时钟
+void delay_init()
+{
+
+	systick_clksource_set(SYSTICK_CLKSOURCE_HCLK_DIV8);	//选择外部时钟  HCLK/8
+	fac_us=SystemCoreClock/8000000;				//为系统时钟的1/8  
+
+	fac_ms=(uint16_t)fac_us*1000;					//非OS下,代表每个ms需要的systick时钟数   
+}								    
+
+//延时nus
+//nus为要延时的us数.		    								   
+void delay_us(uint32_t nus)
+{		
+	uint32_t temp;	    	 
+	SysTick->LOAD=nus*fac_us; 					//时间加载	  		 
+	SysTick->VAL=0x00;        					//清空计数器
+	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数	  
+	do
+	{
+		temp=SysTick->CTRL;
+	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
+	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
+	SysTick->VAL =0X00;      					 //清空计数器	 
+}
+//延时nms
+//注意nms的范围
+//SysTick->LOAD为24位寄存器,所以,最大延时为:
+//nms<=0xffffff*8*1000/SYSCLK
+//SYSCLK单位为Hz,nms单位为ms
+//对72M条件下,nms<=1864 
+void delay_ms(uint16_t nms)
+{	 		
+#if TIMER	
+	 delay_counter = 0; // 清零延时计数器
+   while (delay_counter  < nms); // 等待延时计数器达到指定的延时时间	
+#else   
+	uint32_t temp;		   
+	SysTick->LOAD=(uint32_t)nms*fac_ms;				//时间加载(SysTick->LOAD为24bit)
+	SysTick->VAL =0x00;							//清空计数器
+	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//开始倒数  
+	do
+	{
+		temp=SysTick->CTRL;
+	}while((temp&0x01)&&!(temp&(1<<16)));		//等待时间到达   
+	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
+	SysTick->VAL =0X00;       					//清空计数器	  	
+#endif
+} 
+
+

+ 4 - 1
app/HW/source/hd_eth.c

@@ -7,6 +7,7 @@
 #include "lwip/dhcp.h"
 #include "tcpip.h"
 #include "lwip/netif.h"
+#include "led.h"
 
 
 volatile uint32_t  EthStatus = 0;
@@ -66,6 +67,8 @@ static void enet_mac_dma_config(void)
 		if( enet_init(ENET_AUTO_NEGOTIATION, ENET_AUTOCHECKSUM_DROP_FAILFRAMES, ENET_BROADCAST_FRAMES_PASS))
 		{
 			EthStatus = ETH_INIT_FLAG;
+			gd_eval_led_init(LED_NETSTATE);
+			gd_eval_led_on(LED_NETSTATE);
 		}
     else
 		{
@@ -103,7 +106,7 @@ static void enet_gpio_config(void)
     rcu_periph_clock_enable(RCU_GPIOC);
     rcu_periph_clock_enable(RCU_AF);
   
-    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);
+//    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);
   
 #ifdef MII_MODE 
   

+ 16 - 1
app/HW/source/netconf.c

@@ -150,6 +150,7 @@ void lwip_stack_init(void)
     \param[out] none
     \retval     none
 */
+volatile int dhcp_done;
 void dhcp_task(void * pvParameters)
 {
     struct ip_addr ipaddr;
@@ -171,6 +172,7 @@ void dhcp_task(void * pvParameters)
             ip_address = g_mynetif.ip_addr.addr;
 
             if(0 != ip_address){ 
+								dhcp_done=1;
                 dhcp_state = DHCP_ADDRESS_ASSIGNED;
                 /* stop DHCP */
                 dhcp_stop(&g_mynetif);
@@ -274,7 +276,20 @@ void ETH_link_callback(struct netif *netif)
         enet_phy_write_read(ENET_PHY_READ, PHY_ADDRESS, PHY_REG_BSR, &phy_value);
         phy_value &= PHY_AUTONEGO_COMPLETE;
         timeout++;
-    }while((RESET == phy_value) && (timeout < PHY_READ_TO));	
+    }while((RESET == phy_value) && (timeout < PHY_READ_TO));
+/*
+     enet_phy_write_read(ENET_PHY_READ, PHY_ADDRESS, PHY_SR, &phy_value);  
+        if((uint16_t)RESET != (phy_value & PHY_DUPLEX_STATUS)){
+            media_temp = ENET_MODE_FULLDUPLEX;
+        }else{
+            media_temp = ENET_MODE_HALFDUPLEX;
+        }
+        if((uint16_t)RESET !=(phy_value & PHY_SPEED_STATUS)){
+            media_temp |= ENET_SPEEDMODE_10M;
+        }else{
+            media_temp |= ENET_SPEEDMODE_100M;
+        }
+*/			
 		enet_enable();
 		netif_set_up(&g_mynetif);
 	}

+ 45 - 0
app/HW/source/timer.c

@@ -0,0 +1,45 @@
+#include "timer.h"
+
+volatile uint32_t delay_counter = 0; // 延时计数器
+void timer5_init(){
+	rcu_periph_clock_enable(RCU_TIMER5); // 使能Timer5时钟
+
+    timer_parameter_struct timer_init_struct;
+    timer_deinit(TIMER5); // 复位Timer5配置
+
+    timer_struct_para_init(&timer_init_struct);
+
+    timer_init_struct.prescaler = 119; // 定时器时钟为120MHz
+    timer_init_struct.alignedmode = TIMER_COUNTER_EDGE; // 边沿对齐模式
+    timer_init_struct.counterdirection = TIMER_COUNTER_UP; // 向上计数
+    timer_init_struct.period = 999; // 计数器周期为1000,即10kHz下1秒钟
+    timer_init_struct.clockdivision = TIMER_CKDIV_DIV1; // 时钟分频1
+    timer_init_struct.repetitioncounter = 0; // 重复计数器值
+
+    timer_init(TIMER5, &timer_init_struct);
+
+    timer_interrupt_enable(TIMER5, TIMER_INT_UP); // 使能Timer5更新中断
+    nvic_irq_enable(TIMER5_IRQn, 0, 0); // 使能Timer5中断,并设置优先级为0
+    timer_enable(TIMER5); // 启动Timer5
+}
+//启动定时器
+void timer5_start(void){
+	timer_enable(TIMER5);
+}
+//关闭定时器
+void timer5_stop(void){
+	timer_disable(TIMER5);
+}
+
+void TIMER5_IRQHandler(void)
+{
+    if (timer_interrupt_flag_get(TIMER5, TIMER_INT_UP) != RESET)
+    {
+        timer_interrupt_flag_clear(TIMER5, TIMER_INT_UP); // 清除中断标志
+        delay_counter++; // 延时计数器加1
+    }
+}
+
+
+
+

+ 29 - 16
app/HW/source/usart.c

@@ -1,4 +1,8 @@
 #include "usart.h"
+#include "mmodbus.h"
+#include "dlt645.h"
+
+
 void nvic_config(void);
 void gd_485_DE_pin_init(void)
 {
@@ -83,11 +87,12 @@ void config_485_port(uint32_t com,uint32_t baudrate, uint8_t databits, uint8_t s
 			usart_transmit_config(com, USART_TRANSMIT_ENABLE);
 			/* 使能串口 */
 			usart_enable(com);
-//			nvic_config();
-//		  usart_interrupt_enable(com, USART_INT_RBNE);
-//			usart_interrupt_enable(com, USART_INT_IDLE);
+			nvic_config();		  
+			usart_interrupt_enable(com, USART_INT_RBNE);
+			usart_interrupt_enable(com, USART_INT_IDLE);
 			//解决485第一个帧数据第一个字节丢失问题
 			usart_flag_clear(COM_485,USART_FLAG_TC);
+//			usart_interrupt_flag_clear(COM_485, USART_INT_FLAG_RBNE);
 }
 
 void nvic_config(void)
@@ -96,18 +101,26 @@ void nvic_config(void)
 }
 void USART0_IRQHandler(void)
 {
-	 if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))
-  {
-   usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
-  }
-
-  if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE))
-  {
-		usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
-  }
-  else
-  {
-    usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
-  }
+		mmodbus_callback();
 }
 
+//void USART0_IRQHandler(void)
+//{
+//  if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE))
+//  {
+//   usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
+//  }
+
+//  if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE))
+//  {
+//		usart_data_receive(USART0);
+//		usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
+//  }
+//  else
+//  {
+//		usart_data_receive(USART0);
+//    usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
+//  }
+//}
+
+

BIN
app/MDK/Objects/dtu_simple.axf


Plik diff jest za duży
+ 290 - 125
app/MDK/dtu_simple.uvoptx


Plik diff jest za duży
+ 82 - 6
app/MDK/dtu_simple.uvprojx


+ 45 - 0
app/System/include/data_task.h

@@ -0,0 +1,45 @@
+#ifndef __TASK_H
+#define	__TASK_H
+#include "gd32f30x.h"
+#include "gateway_message.h"
+#include "mqttclient.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "include.h"
+
+
+//主要的数据处理线程
+#define DATA_TASK_PRIO    3 
+#define DATA_STK_SIZE  2*1024
+
+#define GetCurrentTime()  xTaskGetTickCount()
+
+extern void data_task(void *pdata);
+void  data_task_creat(void);
+
+
+/* 写入modbus寄存器 */
+void write_modbus_data(char* cJSONstring);
+/* 发送至mqtt */
+void send_mqtt(char*buf);
+/* 读取设备数据 */
+int read_device_data(DEVICE_PARAMS *current_device,char* buf, char* string);
+///* 读取设备数据 */
+//int read_device_data1(DEVICE_PARAMS *current_device,char* buf);
+//int read_device_data2(DEVICE_PARAMS *current_device,char* buf);
+
+typedef struct __JSON_CMD{
+	char deviceId[25];
+	short power;
+	short temp;
+	short mode;
+	short fan;
+	uint16_t slaveAddress;
+	uint16_t registerAddress;
+	uint8_t function;
+	uint8_t cmd;
+}JSON_CMD;
+
+
+#endif

+ 145 - 0
app/System/include/gateway_message.h

@@ -0,0 +1,145 @@
+#ifndef __GATEWAY_MESSAGE_H
+#define __GATEWAY_MESSAGE_H
+#include "gd32f30x.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
+// 网关所存储的modbus写命令
+typedef struct _GATEWAY_WRITE_MODBUS_COMMAND
+{
+	uint16_t registerByteNum;
+	uint8_t slaveAddress;
+	uint8_t functionCode;
+	uint8_t dataType;          //数据类型
+	uint8_t keyword[20]; // 所写属性的名称
+	uint8_t bigLittleFormat;
+	uint16_t registerAddress;	// 寄存器地址
+	uint8_t write_command_flag; // 是否成功写入的标志
+	struct _GATEWAY_WRITE_MODBUS_COMMAND *nextParams;
+} GATEWAY_WRITE_MODBUS_COMMAND;
+
+// 网关所存储的modbus读命令
+typedef struct _GATEWAY_READ_MODBUS_COMMAND
+{
+	uint8_t slaveAddress;
+	uint8_t functionCode;
+	uint8_t keyword[20]; // 所读属性的名称
+	uint16_t registerAddress;  // 寄存器地址
+	uint8_t read_command_flag; // 是否成功读取到的标志
+	uint32_t value;          //读取到的数据值
+	uint16_t registerByteNum;
+	uint8_t decimalPoint;
+	struct _GATEWAY_READ_MODBUS_COMMAND *nextParams;
+} GATEWAY_READ_MODBUS_COMMAND;
+
+
+// 节点所存储都DLT645读指令
+typedef struct _GATEWAY_READ_DLT645_COMMAND
+{
+	uint8_t deviceID645[6];
+	uint8_t keyword[20];   // 所读属性的名称
+	uint32_t Identification; // 645数据标识
+	uint8_t data[9];	   // 读到的数据
+	uint8_t rxLen;		   // 从机应答值的长度
+	struct _GATEWAY_READ_DLT645_COMMAND *nextParams;
+} GATEWAY_READ_DLT645_COMMAND;
+
+typedef struct _PARAMS_PROTOCOL_COMMAND
+{
+	GATEWAY_READ_MODBUS_COMMAND   *gateway_read_modbus_command;
+	GATEWAY_WRITE_MODBUS_COMMAND  *gateway_write_modbus_command;
+	GATEWAY_READ_DLT645_COMMAND   *gateway_read_dlt645_command;
+}PARAMS_PROTOCOL_COMMAND;
+
+
+// 节点包含的设备信息
+typedef struct _DEVICE_PARAMS
+{
+	uint8_t aliveflag; // 存活证明(由轮询来进行保证,当有轮询回应是确定其存活,当链路变化时立即上报设备已经死去,当轮询有相应的相应值时去上报已经存活)
+	uint8_t deviceID[20];
+	uint8_t protocol;  // 所属协议类型   1:modbus read 2:modbus write 3:dlt97  4:dlt07    一个设备只能存在一个协议	
+	uint8_t MDBbigLittleFormat;
+	uint8_t MDBdataType;	
+	PARAMS_PROTOCOL_COMMAND	*params;
+	struct _DEVICE_PARAMS *nextDevice; // 指向下一个设备地址
+} DEVICE_PARAMS;
+
+
+// 网关包含的设备信息
+typedef struct _GATEWAY_PARAMS
+{
+	uint8_t data_valid_flag;  // 数据有效标志  0xF1:有效  其它:无效
+	uint8_t host[20];		  // MQTT服务器地址
+	uint16_t port;			  // MQTT服务器端口号
+//	uint16_t port[2];
+	uint8_t messageTopic[50]; // MQTT消息主题
+	uint8_t commandTopic[50]; // MQTT指令主题
+	uint8_t username[20];			//MQTT用户名
+	uint8_t passwd[20];				// MQTT用户密码
+	uint8_t deviceId[25];	  // 设备ID
+	uint8_t dataSource;		  // 协议类型                 0 保留 1 表示645协议 2表示modbus协议
+	uint8_t dataType645;	  // 645协议数据类型          0 保留 1 表示07版本  2表示97版本
+	uint32_t pollTime;		  // 轮询时间
+	uint32_t inboundTime;
+	uint8_t state;			 // 检测是否上位机配置过当上位机配置过该状态位,则以后均不走http获取相应配置 置位值为0xF1
+	uint8_t gatewayId[10];	 // 固化信息
+	uint8_t gatewayMode[10]; // 工作模式、后续版本迭代使用
+		uint8_t gateName[10];		// 网关相关信息
+
+	// 包含的设备结构体
+	uint8_t deviceCount;
+	DEVICE_PARAMS *device_params;
+		// 外设的串口工作属性仅只有一个
+	uint32_t baudrate;	 // 波特率
+	uint8_t dataBits;	 // 数据位
+	uint8_t checkBit;	 // 校验位
+	uint8_t stopBit;	 // 停止位
+	uint8_t flowControl; // 流控制
+	uint8_t parity;				//校验位
+	uint8_t bandwidth;	
+} GATEWAY_PARAMS;
+
+void addGatewayParams(char *gatewayString);
+
+int parseIntField(const char *data, const char *field);
+void parseStringField(const char *data, const char *field, char *value);
+
+GATEWAY_PARAMS *get_gateway_config_params(void);
+int extract_substring(const char *input_string, const char *start_token, const char *end_token, char *result);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void analysis_read_data(DEVICE_PARAMS *device, char* buf);
+
+typedef struct _MODBUS_READ_DATA
+{
+	uint8_t deviceId[20];
+	// modbus读出的数据名
+	uint8_t power;	
+	uint8_t temp;
+	uint8_t mode;
+	uint8_t fan;
+	uint8_t roomTemp;
+	uint8_t fault;
+	
+	struct _MODBUS_READ_DATA *nextParams;
+} MODBUS_READ_DATA;
+
+typedef struct _DLT_READ_DATA
+{
+	uint8_t deviceId[20];
+	// dlt读出的数据名
+	uint8_t deviceID645[6];
+	uint8_t keyword[20];   // 所读属性的名称
+	uint32_t Identification; // 645数据标识
+	uint8_t data[9];
+	
+	struct _DLT_READ_DATA *nextParams;
+} DLT_READ_DATA;
+
+typedef struct _READ_DATA
+{
+	MODBUS_READ_DATA   *read_modbus_data;
+	DLT_READ_DATA  		 *read_dlt645_data;
+}READ_DATA;
+#endif

+ 4 - 1
app/System/include/gd32_flash.h

@@ -1,10 +1,13 @@
 #ifndef GD32_FLASH_H
 #define GD32_FLASH_H
-
+#include "stdint.h"
 
 #define FMC_PAGE_SIZE           ((uint16_t)0x1000U)
 #define FMC_WRITE_START_ADDR    ((uint32_t)0x08038800U)
 #define FMC_WRITE_END_ADDR      ((uint32_t)0x0803FFFFU)
 void gd32_flash_test();
+
+void GD32_EraseFlash(uint16_t start, uint16_t num);
+int save_config_params(char *params);
 int read_data_from_flash(void *buffer);
 #endif

+ 471 - 0
app/System/include/jsmn.h

@@ -0,0 +1,471 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef JSMN_H
+#define JSMN_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef JSMN_STATIC
+#define JSMN_API static
+#else
+#define JSMN_API extern
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ * 	o Object
+ * 	o Array
+ * 	o String
+ * 	o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+  JSMN_UNDEFINED = 0,
+  JSMN_OBJECT = 1 << 0,
+  JSMN_ARRAY = 1 << 1,
+  JSMN_STRING = 1 << 2,
+  JSMN_PRIMITIVE = 1 << 3
+} jsmntype_t;
+
+enum jsmnerr {
+  /* Not enough tokens were provided */
+  JSMN_ERROR_NOMEM = -1,
+  /* Invalid character inside JSON string */
+  JSMN_ERROR_INVAL = -2,
+  /* The string is not a full JSON packet, more bytes expected */
+  JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * type		type (object, array, string etc.)
+ * start	start position in JSON data string
+ * end		end position in JSON data string
+ */
+typedef struct jsmntok {
+  jsmntype_t type;
+  int start;
+  int end;
+  int size;
+#ifdef JSMN_PARENT_LINKS
+  int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string.
+ */
+typedef struct jsmn_parser {
+  unsigned int pos;     /* offset in the JSON string */
+  unsigned int toknext; /* next token to allocate */
+  int toksuper;         /* superior token node, e.g. parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each
+ * describing
+ * a single JSON object.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                        jsmntok_t *tokens, const unsigned int num_tokens);
+
+#ifndef JSMN_HEADER
+/**
+ * Allocates a fresh unused token from the token pool.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+                                   const size_t num_tokens) {
+  jsmntok_t *tok;
+  if (parser->toknext >= num_tokens) {
+    return NULL;
+  }
+  tok = &tokens[parser->toknext++];
+  tok->start = tok->end = -1;
+  tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+  tok->parent = -1;
+#endif
+  return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+                            const int start, const int end) {
+  token->type = type;
+  token->start = start;
+  token->end = end;
+  token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+                                const size_t len, jsmntok_t *tokens,
+                                const size_t num_tokens) {
+  jsmntok_t *token;
+  int start;
+
+  start = parser->pos;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+    /* In strict mode primitive must be followed by "," or "}" or "]" */
+    case ':':
+#endif
+    case '\t':
+    case '\r':
+    case '\n':
+    case ' ':
+    case ',':
+    case ']':
+    case '}':
+      goto found;
+    default:
+                   /* to quiet a warning from gcc*/
+      break;
+    }
+    if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+      parser->pos = start;
+      return JSMN_ERROR_INVAL;
+    }
+  }
+#ifdef JSMN_STRICT
+  /* In strict mode primitive must be followed by a comma/object/array */
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+#endif
+
+found:
+  if (tokens == NULL) {
+    parser->pos--;
+    return 0;
+  }
+  token = jsmn_alloc_token(parser, tokens, num_tokens);
+  if (token == NULL) {
+    parser->pos = start;
+    return JSMN_ERROR_NOMEM;
+  }
+  jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+  token->parent = parser->toksuper;
+#endif
+  parser->pos--;
+  return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+                             const size_t len, jsmntok_t *tokens,
+                             const size_t num_tokens) {
+  jsmntok_t *token;
+
+  int start = parser->pos;
+  
+  /* Skip starting quote */
+  parser->pos++;
+  
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    char c = js[parser->pos];
+
+    /* Quote: end of string */
+    if (c == '\"') {
+      if (tokens == NULL) {
+        return 0;
+      }
+      token = jsmn_alloc_token(parser, tokens, num_tokens);
+      if (token == NULL) {
+        parser->pos = start;
+        return JSMN_ERROR_NOMEM;
+      }
+      jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+      token->parent = parser->toksuper;
+#endif
+      return 0;
+    }
+
+    /* Backslash: Quoted symbol expected */
+    if (c == '\\' && parser->pos + 1 < len) {
+      int i;
+      parser->pos++;
+      switch (js[parser->pos]) {
+      /* Allowed escaped symbols */
+      case '\"':
+      case '/':
+      case '\\':
+      case 'b':
+      case 'f':
+      case 'r':
+      case 'n':
+      case 't':
+        break;
+      /* Allows escaped symbol \uXXXX */
+      case 'u':
+        parser->pos++;
+        for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
+             i++) {
+          /* If it isn't a hex character we have an error */
+          if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
+                (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
+                (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+            parser->pos = start;
+            return JSMN_ERROR_INVAL;
+          }
+          parser->pos++;
+        }
+        parser->pos--;
+        break;
+      /* Unexpected symbol */
+      default:
+        parser->pos = start;
+        return JSMN_ERROR_INVAL;
+      }
+    }
+  }
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                        jsmntok_t *tokens, const unsigned int num_tokens) {
+  int r;
+  int i;
+  jsmntok_t *token;
+  int count = parser->toknext;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+    char c;
+    jsmntype_t type;
+
+    c = js[parser->pos];
+    switch (c) {
+    case '{':
+    case '[':
+      count++;
+      if (tokens == NULL) {
+        break;
+      }
+      token = jsmn_alloc_token(parser, tokens, num_tokens);
+      if (token == NULL) {
+        return JSMN_ERROR_NOMEM;
+      }
+      if (parser->toksuper != -1) {
+        jsmntok_t *t = &tokens[parser->toksuper];
+#ifdef JSMN_STRICT
+        /* In strict mode an object or array can't become a key */
+        if (t->type == JSMN_OBJECT) {
+          return JSMN_ERROR_INVAL;
+        }
+#endif
+        t->size++;
+#ifdef JSMN_PARENT_LINKS
+        token->parent = parser->toksuper;
+#endif
+      }
+      token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+      token->start = parser->pos;
+      parser->toksuper = parser->toknext - 1;
+      break;
+    case '}':
+    case ']':
+      if (tokens == NULL) {
+        break;
+      }
+      type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+      if (parser->toknext < 1) {
+        return JSMN_ERROR_INVAL;
+      }
+      token = &tokens[parser->toknext - 1];
+      for (;;) {
+        if (token->start != -1 && token->end == -1) {
+          if (token->type != type) {
+            return JSMN_ERROR_INVAL;
+          }
+          token->end = parser->pos + 1;
+          parser->toksuper = token->parent;
+          break;
+        }
+        if (token->parent == -1) {
+          if (token->type != type || parser->toksuper == -1) {
+            return JSMN_ERROR_INVAL;
+          }
+          break;
+        }
+        token = &tokens[token->parent];
+      }
+#else
+      for (i = parser->toknext - 1; i >= 0; i--) {
+        token = &tokens[i];
+        if (token->start != -1 && token->end == -1) {
+          if (token->type != type) {
+            return JSMN_ERROR_INVAL;
+          }
+          parser->toksuper = -1;
+          token->end = parser->pos + 1;
+          break;
+        }
+      }
+      /* Error if unmatched closing bracket */
+      if (i == -1) {
+        return JSMN_ERROR_INVAL;
+      }
+      for (; i >= 0; i--) {
+        token = &tokens[i];
+        if (token->start != -1 && token->end == -1) {
+          parser->toksuper = i;
+          break;
+        }
+      }
+#endif
+      break;
+    case '\"':
+      r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+      if (r < 0) {
+        return r;
+      }
+      count++;
+      if (parser->toksuper != -1 && tokens != NULL) {
+        tokens[parser->toksuper].size++;
+      }
+      break;
+    case '\t':
+    case '\r':
+    case '\n':
+    case ' ':
+      break;
+    case ':':
+      parser->toksuper = parser->toknext - 1;
+      break;
+    case ',':
+      if (tokens != NULL && parser->toksuper != -1 &&
+          tokens[parser->toksuper].type != JSMN_ARRAY &&
+          tokens[parser->toksuper].type != JSMN_OBJECT) {
+#ifdef JSMN_PARENT_LINKS
+        parser->toksuper = tokens[parser->toksuper].parent;
+#else
+        for (i = parser->toknext - 1; i >= 0; i--) {
+          if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
+            if (tokens[i].start != -1 && tokens[i].end == -1) {
+              parser->toksuper = i;
+              break;
+            }
+          }
+        }
+#endif
+      }
+      break;
+#ifdef JSMN_STRICT
+    /* In strict mode primitives are: numbers and booleans */
+    case '-':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case 't':
+    case 'f':
+    case 'n':
+      /* And they must not be keys of the object */
+      if (tokens != NULL && parser->toksuper != -1) {
+        const jsmntok_t *t = &tokens[parser->toksuper];
+        if (t->type == JSMN_OBJECT ||
+            (t->type == JSMN_STRING && t->size != 0)) {
+          return JSMN_ERROR_INVAL;
+        }
+      }
+#else
+    /* In non-strict mode every unquoted value is a primitive */
+    default:
+#endif
+      r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+      if (r < 0) {
+        return r;
+      }
+      count++;
+      if (parser->toksuper != -1 && tokens != NULL) {
+        tokens[parser->toksuper].size++;
+      }
+      break;
+
+#ifdef JSMN_STRICT
+    /* Unexpected char in strict mode */
+    default:
+      return JSMN_ERROR_INVAL;
+#endif
+    }
+  }
+
+  if (tokens != NULL) {
+    for (i = parser->toknext - 1; i >= 0; i--) {
+      /* Unmatched opened object or array */
+      if (tokens[i].start != -1 && tokens[i].end == -1) {
+        return JSMN_ERROR_PART;
+      }
+    }
+  }
+
+  return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser) {
+  parser->pos = 0;
+  parser->toknext = 0;
+  parser->toksuper = -1;
+}
+
+#endif /* JSMN_HEADER */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* JSMN_H */

+ 16 - 0
app/System/include/protocol.h

@@ -0,0 +1,16 @@
+#ifndef __PROTOCOL_H
+#define	__PROTOCOL_H
+
+#include "gateway_message.h"
+// 解析发过来的数据是modbus还是dlt645 
+#define	MODBUS_WRITE 4                //本机用于区分读写
+#define	MODBUS_READ 3
+#define	DLT645_07 1
+#define	DLT645_97 2
+extern uint8_t protocol_485;
+
+
+#define	MODBUS 3
+
+
+#endif

+ 11 - 0
app/System/include/sys_http.h

@@ -0,0 +1,11 @@
+#ifndef SYS_HTTP_H
+#define SYS_HTTP_H
+#include "stdint.h"
+
+extern uint8_t  load_http_config;
+void http_getDemo(void);
+
+void http_postDemo(void);
+#endif 
+
+

+ 5 - 2
app/System/include/sys_mqtt.h

@@ -2,13 +2,16 @@
 #define SYS_MQTT_H
 #include <stdint.h>
 #include "mqttclient.h"
+
+extern int mqtt_connectFlag;
+extern	QueueHandle_t xQueue1;
 struct Pub_Queue
 {
 	uint16_t pubLength;
 	mqtt_qos_t qos;
 	char *pub_topic;
-	uint8_t *message;
+	char *message;
 };
 void mqtt_task_creat();
-void mqtt_publish_data(uint8_t *payload,mqtt_qos_t qos,uint16_t pub_length,char *topic);
+void mqtt_publish_data(char *payload,mqtt_qos_t qos,uint16_t pub_length,char *topic);
 #endif

+ 416 - 0
app/System/source/data_task.c

@@ -0,0 +1,416 @@
+#include "data_task.h"
+#include "usart.h"
+#include "sys_mqtt.h"
+#include "sys_http.h"
+#include "mmodbus.h"
+#include "dlt645.h"
+#include "dlt645_1997_private.h"
+#include "dlt645_port.h"
+#include "gd32_flash.h"
+#include "protocol.h"
+#include "sys_http.h"
+#include "jsmn.h"
+#include "timer.h"
+
+uint8_t time_count = 0, jsonCunt = 0, count = 0;
+uint8_t protocol_485;
+int time1,time2;
+int ID = 0;
+
+void data_task(void *pdata)
+{
+		 
+		dlt645_init(1);
+		mmodbus_init(1);
+		while(!load_http_config)
+		{
+			vTaskDelay(100);
+		}
+
+		portENTER_CRITICAL();
+		char *device_config_json=pvPortMalloc( 10 *1024 );
+		read_data_from_flash(device_config_json);
+		addGatewayParams(device_config_json);	
+		vPortFree(device_config_json);
+		device_config_json = NULL;
+		portEXIT_CRITICAL();
+		
+		GATEWAY_PARAMS *get;
+		get= get_gateway_config_params();
+		DEVICE_PARAMS *current_device=get->device_params;
+		
+		char *buf = pvPortMalloc(1024);	// 接收读取的数据
+		char *string = pvPortMalloc(1024);	// 接收读取的数据
+		memset(buf,0,strlen(buf));
+		memset(string,0,strlen(string));
+		
+		while (current_device!=NULL)
+		{		
+			time1 = GetCurrentTime();
+			if(mqtt_connectFlag)
+			{
+				if(jsonCunt && time2  <= time1 - ( 10 * 1000))// 60s进行一次全数据发送
+				{
+						read_device_data(current_device, buf, string);
+						send_mqtt(buf);
+						memset(buf,0,strlen(buf));					
+						time2 = GetCurrentTime();
+					current_device=get->device_params;
+				}
+				else
+				{
+					read_device_data(current_device, buf, string);
+					if(count > 0)// count检测是否含有数据
+					{
+						send_mqtt(string);
+						memset(string,0,strlen(string));
+						current_device=get->device_params;
+						count = 0;
+						if(!time_count)
+						{
+							jsonCunt = 1;
+							time_count = 1;
+							time2 = GetCurrentTime();
+						}
+					}
+				}	
+				memset(buf,0,strlen(buf));				
+			}		
+			
+			vTaskDelay(100);
+		}	
+		vPortFree(buf);
+		buf = NULL;
+		
+}	
+
+/*
+*********************************************************************************************************
+*	函 数 名: int READ_MODBUS_DATA(DEVICE_PARAMS *device)
+*	功能说明: 读取当前节点上的modbus数据
+*	形    参: DEVICE_PARAMS *device  当前设备
+*	返 回 值: 1: 成功 0:失败
+*********************************************************************************************************
+*/
+int read_device_data(DEVICE_PARAMS *device, char* buf, char* string)
+{
+		DEVICE_PARAMS *current_device=device;	
+		GATEWAY_READ_MODBUS_COMMAND *currentModbusParams = current_device->params->gateway_read_modbus_command;
+		GATEWAY_READ_DLT645_COMMAND *currentDLT645Params = current_device->params->gateway_read_dlt645_command;	
+	
+		while(current_device->params != NULL)
+		{				
+				if (current_device->protocol == MODBUS_READ)
+				{
+						protocol_485=1;
+						uint8_t state;
+						uint16_t data[currentModbusParams->registerByteNum /2]; // modbus寄存器长度
+						uint8_t data1[currentModbusParams->registerByteNum /2];
+						mmodbus_set16bitOrder(current_device->MDBbigLittleFormat);
+						// 读水阀状态
+						if(currentModbusParams->functionCode == 0x01)
+						{
+							bool success = mmodbus_readCoil(currentModbusParams->slaveAddress,
+																		 currentModbusParams->registerByteNum /2,
+																		 data1);
+							if(success)
+							{
+								uint8_t value;
+								value = data1[0];
+								if(value == 0)
+								{
+								sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\":close},", 
+																									current_device->deviceID, currentModbusParams->keyword);
+								}else{
+									sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\":open},", 
+																									current_device->deviceID, currentModbusParams->keyword);
+								}
+							}
+							currentModbusParams = currentModbusParams->nextParams;
+								if (currentModbusParams == NULL)	
+								{
+										current_device = current_device->nextDevice;
+										currentModbusParams = current_device->params->gateway_read_modbus_command;
+										if(current_device == NULL)
+										{
+												sprintf(buf + strlen(buf) - 1, ""); 
+												return 1;
+										}
+								}		
+						}
+						// 读单个寄存器
+						if (currentModbusParams->functionCode == 0x03)
+						{
+//								bool success = mmodbus_readHoldingRegisters16i(0x17,0x00,0x02,data);
+								bool success = mmodbus_readHoldingRegisters16i(currentModbusParams->slaveAddress,
+																															 currentModbusParams->registerAddress,
+																															 currentModbusParams->registerByteNum /2,
+																															 data);
+
+								if (success)
+								{
+										uint32_t value;
+										if (currentModbusParams->registerByteNum == 4)
+										{
+												value = (uint32_t)data[0] | data[1];
+										}
+										else if (currentModbusParams->registerByteNum == 2)
+										{
+												value = data[0];
+										}
+										if((value - currentModbusParams->value) != 0)
+										{
+												count++;
+												sprintf(string + strlen(string), "{\"deviceId\":\"%s\",\"%s\":%d},", 
+																									current_device->deviceID, currentModbusParams->keyword, value);
+										}
+										else
+										{									
+												sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\":%d},", 
+																									current_device->deviceID, currentModbusParams->keyword, value);
+										}
+										if (currentModbusParams->decimalPoint == 0)
+										{
+												currentModbusParams->value = value;
+
+										}
+										else
+										{
+//												float convertedValue = (float)value / pow(10, currentModbusParams->decimalPoint);
+//												currentModbusParams->value=convertedValue;
+										}
+																	
+								}					
+								currentModbusParams = currentModbusParams->nextParams;
+								if (currentModbusParams == NULL)	
+								{
+										current_device = current_device->nextDevice;
+										currentModbusParams = current_device->params->gateway_read_modbus_command;
+										if(current_device == NULL)
+										{
+												sprintf(buf + strlen(buf) - 1, ""); 
+												sprintf(string + strlen(string) - 1, ""); 
+												return 1;
+										}
+								}												
+						}
+						// 开关水阀
+						if(currentModbusParams->functionCode == 0x05)
+						{
+							bool success = mmodbus_writeCoil(currentModbusParams->slaveAddress,
+																							 currentModbusParams->registerByteNum /2,
+																							 state);
+							if(success)
+							{
+								
+									sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\": success},", 
+																									current_device->deviceID, currentModbusParams->keyword);
+							}
+							else{
+									sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\": fail},", 
+																									current_device->deviceID, currentModbusParams->keyword);
+							}
+							currentModbusParams = currentModbusParams->nextParams;
+							if (currentModbusParams == NULL)	
+							{
+									current_device = current_device->nextDevice;
+									currentModbusParams = current_device->params->gateway_read_modbus_command;
+									if(current_device == NULL)
+									{
+											sprintf(buf + strlen(buf) - 1, ""); 
+											return 1;
+									}
+							}
+						}
+						// 写单个寄存器
+						if(currentModbusParams->functionCode == 0x06)
+						{
+							bool success = mmodbus_writeHoldingRegisters16i(currentModbusParams->slaveAddress,
+																		 currentModbusParams->registerAddress,
+																		 currentModbusParams->registerByteNum /2,
+																		 data);
+							if(success)
+							{
+								sprintf(buf + strlen(buf), "{\"deviceId\":\"%s\",\"%s\":write success},", 
+																									current_device->deviceID, currentModbusParams->keyword);
+							}
+							currentModbusParams = currentModbusParams->nextParams;
+							if (currentModbusParams == NULL)	
+							{
+									current_device = current_device->nextDevice;
+									currentModbusParams = current_device->params->gateway_read_modbus_command;
+									if(current_device == NULL)
+									{
+											sprintf(buf + strlen(buf) - 1, ""); 
+											return 1;
+									}
+							}
+							
+						}
+
+				}
+				else if (current_device->protocol == DLT645_2007 || current_device->protocol == DLT645_97)
+				{
+						protocol_485=2;
+						uint8_t read_buf[10];
+						uint32_t dltValue;
+						
+						currentDLT645Params->rxLen = 0;
+						memset(read_buf, 0, 10);
+						memset(currentDLT645Params->data, 0, 10);
+
+						dlt645_set_addr(&dlt645, currentDLT645Params->deviceID645);
+						int8_t rs;
+						if (current_device->protocol == DLT645_2007)
+						{
+								rs = dlt645_read_data(&dlt645, currentDLT645Params->Identification, read_buf, DLT645_2007);
+						}
+						else if (current_device->protocol == DLT645_1997)
+						{
+								rs = dlt645_read_data(&dlt645, currentDLT645Params->Identification, read_buf, DLT645_1997);
+						}
+						if (rs != -1)
+						{
+								if (rs <= 4)
+								{
+										memcpy(currentDLT645Params->data, read_buf, 4);
+										currentDLT645Params->rxLen = 4;
+								}
+								else if (rs == 5)
+								{
+										memcpy(currentDLT645Params->data, read_buf, 5);
+										currentDLT645Params->rxLen = 5;
+								}
+							else if (rs > 5)
+								{
+										memcpy(currentDLT645Params->data, read_buf, 9);
+										currentDLT645Params->rxLen = 9;
+								}
+															
+								dltValue = currentDLT645Params->data[0] << 24 | currentDLT645Params->data[1] << 16|
+																		currentDLT645Params->data[2] << 8  | currentDLT645Params->data[3];
+								
+								sprintf(buf + strlen(buf), "{\"identifier\":\"%s\",\"deviceID645\":\"%02x%02x%02x%02x%02x%02x\",\"identifier645\":%d,\"value\":%X}",
+																				currentDLT645Params->keyword, currentDLT645Params->deviceID645[0],
+																				currentDLT645Params->deviceID645[1],currentDLT645Params->deviceID645[2],
+																				currentDLT645Params->deviceID645[3],currentDLT645Params->deviceID645[4],
+																				currentDLT645Params->deviceID645[5],currentDLT645Params->Identification,dltValue);
+								count++;
+			
+						}
+		
+								currentDLT645Params = currentDLT645Params->nextParams;		
+								if (currentDLT645Params == NULL)	
+								{
+										current_device = current_device->nextDevice;
+										currentDLT645Params = current_device->params->gateway_read_dlt645_command;
+										if(current_device == NULL)
+										{
+												sprintf(buf + strlen(buf) - 1, ""); 
+												return 1;
+										}
+								}										
+				}			
+				
+		}		
+		return 1;
+	
+}
+
+/*
+*********************************************************************************************************
+*	函 数 名: void send_mqtt(char*buf, int jsonCunt)
+*	功能说明: 将数据发送到mqtt
+*	形    参: 参数1:读取数据 参数2:第一次发送标志
+*	返 回 值: 无
+*********************************************************************************************************
+*/
+void send_mqtt(char*buf){
+		GATEWAY_PARAMS *get;
+		get= get_gateway_config_params();
+//		char *pubJsonString = pvPortMalloc(strlen(buf)); 
+		char pubJsonString[500];
+	  sprintf(pubJsonString,"ID: %d {\"DEVICEID\":\"%s\",\"data\":[%s]}",ID++, get->deviceId, buf);	// 组成要发送的json语句							
+	 	mqtt_qos_t qos = QOS0;
+		uint16_t pub_length = strlen(pubJsonString);
+		mqtt_publish_data(pubJsonString, qos, pub_length, (char*)&get->messageTopic);	
+//		vPortFree(pubJsonString);
+//		pubJsonString = NULL;
+}
+
+/*
+*********************************************************************************************************
+*	函 数 名:void WRITE_MODBUS_DATA(char* cJSONstring)
+*	功能说明: 接收mqtt数据并写入modbus寄存器
+*	形    参:char* cJSONstring mqtt接收到的数据
+*	返 回 值: 无
+*********************************************************************************************************
+*/
+void write_modbus_data(char* JSON_STRING)
+{	
+		JSON_CMD jsonMsg;
+		GATEWAY_PARAMS* get;
+		get = get_gateway_config_params();
+		DEVICE_PARAMS* current_device = get->device_params;
+	
+		parseStringField(JSON_STRING, "\"deviceId\":\"", jsonMsg.deviceId);
+    jsonMsg.function = parseIntField(JSON_STRING, "\"function\":");
+		jsonMsg.cmd = parseIntField(JSON_STRING, "\"cmd\":");
+		jsonMsg.power = parseIntField(JSON_STRING, "\"power\":");
+		jsonMsg.temp = parseIntField(JSON_STRING, "\"temp\":");
+		jsonMsg.mode = parseIntField(JSON_STRING, "\"mode\":");
+		jsonMsg.fan = parseIntField(JSON_STRING, "\"fan\":");
+		
+		while(current_device)
+		{
+				char* device_ID = (char*)current_device->deviceID;
+				GATEWAY_WRITE_MODBUS_COMMAND *currentModbusParams = current_device->params->gateway_write_modbus_command;
+				if(!strcmp(device_ID,jsonMsg.deviceId)) //匹配ID
+				{
+					delay_ms(200);
+					if(jsonMsg.function == 5)
+					// 开关阀门
+					{
+						
+						mmodbus_writeCoil(jsonMsg.slaveAddress,jsonMsg.registerAddress,jsonMsg.cmd);
+					}
+					if(jsonMsg.function == 6)
+					{
+					/* 写入寄存器操作 */
+						if(jsonMsg.power)
+						{
+								mmodbus_writeHoldingRegister16i(currentModbusParams->slaveAddress, 
+																								currentModbusParams->registerAddress, 
+																								jsonMsg.power);
+						}
+						delay_ms(100);
+						if(jsonMsg.temp)
+						{
+								currentModbusParams = currentModbusParams->nextParams;							
+								mmodbus_writeHoldingRegister16i(currentModbusParams->slaveAddress, 
+																								currentModbusParams->registerAddress, 
+																								jsonMsg.temp);	
+						}
+						delay_ms(100);
+						if(jsonMsg.mode)
+						{
+								currentModbusParams = currentModbusParams->nextParams;
+								mmodbus_writeHoldingRegister16i(currentModbusParams->slaveAddress, 
+																								currentModbusParams->registerAddress, 
+																								jsonMsg.mode);
+						}
+						delay_ms(100);
+					  if(jsonMsg.fan)
+						{
+								currentModbusParams = currentModbusParams->nextParams;
+								mmodbus_writeHoldingRegister16i(currentModbusParams->slaveAddress, 
+																								currentModbusParams->registerAddress, 
+																								jsonMsg.fan);	
+						}
+						delay_ms(100);
+					}	
+				}
+				current_device = current_device->nextDevice;
+		}
+}
+

+ 317 - 0
app/System/source/gateway_message.c

@@ -0,0 +1,317 @@
+
+#include "string.h"
+#include <stdlib.h>
+#include "protocol.h"
+#include <stdio.h>   
+#include "gateway_message.h"
+
+
+GATEWAY_PARAMS gateway_config_params = {0};
+
+GATEWAY_PARAMS *get_gateway_config_params()
+{
+    return &gateway_config_params;
+}
+
+void parseStringField(const char *data, const char *field, char *value);
+int parseIntField(const char *data, const char *field);
+void addDevice(char *string);
+int extract_substring(const char *input_string, const char *start_token, const char *end_token, char *result);
+void addSensorListParams(char *paramString, DEVICE_PARAMS *device);
+void addCommandListParams(char *paramString, DEVICE_PARAMS *device);
+/**
+ * @brief  解析输入字符串网关结构体信息,将数据保存
+ * @param  char *gatewayString 输入字符串的数据
+ * @retval 无
+ */
+	void addGatewayParams(char *gatewayString)
+{
+		//gateway_config_params.device_params = NULL;
+		gateway_config_params.port = parseIntField(gatewayString, "\"port\":");
+		gateway_config_params.stopBit = parseIntField(gatewayString, "\"stopBit\":");
+		gateway_config_params.dataBits = parseIntField(gatewayString, "\"dataBit\":");
+		gateway_config_params.baudrate = parseIntField(gatewayString, "\"baudrate\":");
+		gateway_config_params.checkBit = parseIntField(gatewayString, "\"checkBit\":");
+		gateway_config_params.inboundTime= parseIntField(gatewayString, "\"inboundTime\":");
+		
+		parseStringField(gatewayString, "\"host\":\"", (char *)&gateway_config_params.host);
+		parseStringField(gatewayString, "\"deviceId\":\"", (char *)&gateway_config_params.deviceId);
+		parseStringField(gatewayString, "\"commandTopic\":\"", (char *)&gateway_config_params.commandTopic);
+		parseStringField(gatewayString, "\"messageTopic\":\"", (char *)&gateway_config_params.messageTopic);
+		parseStringField(gatewayString, "\"username\":\"", (char *)&gateway_config_params.username);
+		parseStringField(gatewayString, "\"password\":\"", (char *)&gateway_config_params.passwd);
+	
+		char *deviceString = strstr(gatewayString,"deviceList");  //移位置到节点数据开始处
+		
+		
+		while (1)
+    {
+        if (deviceString)
+        {
+           addDevice(deviceString); // 往此地址下挂载设备信息
+           deviceString=deviceString;//重新获取设备字符串的位置
+					 deviceString = strstr(deviceString, "}"); 
+					 deviceString[0]='A';
+					 deviceString++;
+					 if(deviceString[0]==']')
+					 {
+					 break;
+					 }
+        }
+        else
+        {
+            return;
+        }
+    }
+}
+
+/**
+ * @brief  解析输入字段的字符串,解析出属于该节点下的设备信息
+ * @param  uint8_t *string输入的字符串数据,NODE_PARAMS *node节点信息
+ * @retval 无
+ */
+
+void addDevice(char *deviceString)
+{
+    char *paramString = (char *)deviceString; // 属性指针
+		DEVICE_PARAMS *newDevicePage = (DEVICE_PARAMS *)pvPortMalloc(sizeof(DEVICE_PARAMS));    // 创建新设备页
+    newDevicePage->nextDevice = NULL;
+    newDevicePage->protocol = parseIntField(deviceString, "\"protocol\":");
+		newDevicePage->MDBdataType = parseIntField(deviceString, "\"dataType\":");
+		newDevicePage->MDBbigLittleFormat = parseIntField(deviceString, "\"bigLittleFormat\":");
+		
+		parseStringField(deviceString, "\"deviceId\":\"", (char *)&newDevicePage->deviceID);
+		
+    newDevicePage->params = (PARAMS_PROTOCOL_COMMAND *)pvPortMalloc(sizeof(PARAMS_PROTOCOL_COMMAND));
+		memset(newDevicePage->params, 0, sizeof(PARAMS_PROTOCOL_COMMAND));
+    paramString = strstr(paramString, "\"sensorData\":["); // 找到该节点的轮询上发属性
+    while (1)                                              // 此处数据是以数组形式存储所以解析方法和上面不一样
+    {
+        addSensorListParams(paramString, newDevicePage); // 解析一个属性并挂载该属性于该属性下
+				paramString=paramString;
+        paramString = strstr(paramString, "}");          // 移动到下一条属性
+				paramString[0]='A';
+        paramString++;
+        if (paramString[0] == ']')
+        {
+            paramString = (char *)deviceString; // 复原指针位置
+						break;                              // 找到了结束符,跳出循环
+        }
+    }
+		if(newDevicePage->protocol==MODBUS)  //如果为modbus的话解析写指令
+		{
+			paramString=deviceString;                                //移动到最开始的地方
+			newDevicePage->MDBbigLittleFormat = parseIntField(paramString, "\"bigLittleFormat\":");
+      newDevicePage->MDBdataType= parseIntField(paramString, "\"dataType\":");
+		  paramString = strstr(paramString, "\"commandData\":["); // 找到其轮询的写命令
+			if(paramString!=NULL)
+			{
+				while(1)
+				{
+					addCommandListParams(paramString, newDevicePage);
+					paramString = strstr(paramString, "}");
+				  paramString[0]='A';
+					paramString++;
+					if (paramString[0] == ']')
+					{
+						paramString = (char *)deviceString;// 复原指针位置
+						break;														 // 找到了结束符,跳出循环
+					}
+				}
+			}
+		}
+    // 解析下发的mqtt存储信息下发控制指令
+		
+    // 添加设备页到链表末尾
+    if (gateway_config_params.device_params == NULL)
+    {
+        gateway_config_params.device_params = newDevicePage;
+    }
+    else
+    {
+        DEVICE_PARAMS *current = gateway_config_params.device_params;
+        while (current->nextDevice != NULL)
+        {
+            current = current->nextDevice;
+        }
+        current->nextDevice = newDevicePage;
+    }
+		//解析modbus command指令将其加载到设备链表中
+		
+}
+/**
+ * @brief  解析输入字符串的paramString数据,将数据保存到至该设备结构体下,此处解析sensorList
+ * @param  uint8_t *paramString输入的字符串数据,DEVICE_PARAMS *device节点信息
+ * @retval 无
+ */
+void addSensorListParams(char *paramString, DEVICE_PARAMS *device)
+{
+    switch (device->protocol)
+    {
+    case DLT645_97:
+    case DLT645_07:
+		{
+        GATEWAY_READ_DLT645_COMMAND *read_dlt645_command = pvPortMalloc(sizeof(GATEWAY_READ_DLT645_COMMAND));
+        read_dlt645_command->Identification = parseIntField(paramString, "\"identifier645\":");
+        parseStringField(paramString, "\"identifier\":\"", (char *)&read_dlt645_command->keyword);
+        char *string = pvPortMalloc(13);
+        parseStringField(paramString, "\"deviceID645\":\"", string);
+        for (int j = 0; j < 6; j++)
+        {
+          uint8_t byte;
+          sscanf((const char *)&string[j * 2], "%2hhx", &byte);
+          read_dlt645_command->deviceID645[j]=byte;
+        }				
+        vPortFree(string);
+				string = NULL;
+        if (device->params->gateway_read_dlt645_command == NULL)
+        {
+            device->params->gateway_read_dlt645_command = read_dlt645_command;
+        }
+        else
+        {
+            GATEWAY_READ_DLT645_COMMAND *current = device->params->gateway_read_dlt645_command;
+            while (current->nextParams != NULL)
+            {
+                current = current->nextParams;
+            }
+            current->nextParams = read_dlt645_command;
+        }
+			}
+				
+        break;
+    case MODBUS:
+		{
+        GATEWAY_READ_MODBUS_COMMAND *read_modbus_command = pvPortMalloc(sizeof(GATEWAY_READ_MODBUS_COMMAND));
+				parseStringField(paramString,"\"identifier\":\"",(char *)&read_modbus_command->keyword);
+        read_modbus_command->decimalPoint = parseIntField(paramString, "\"precise\":");
+        read_modbus_command->functionCode = parseIntField(paramString, "\"rFunctionCode\":");
+        read_modbus_command->slaveAddress = parseIntField(paramString, "\"slaveAddress\":");
+        read_modbus_command->registerAddress = parseIntField(paramString, "\"registerAddress\":");
+        read_modbus_command->registerByteNum = parseIntField(paramString, "\"registerByteNum\":");
+        
+			if (device->params->gateway_read_modbus_command== NULL)
+        {
+            device->params->gateway_read_modbus_command = read_modbus_command;
+        }
+        else
+        {
+            GATEWAY_READ_MODBUS_COMMAND *current = device->params->gateway_read_modbus_command;
+            while (current->nextParams != NULL)
+            {
+                current = current->nextParams;
+            }
+            current->nextParams = read_modbus_command;
+        }
+			}
+        break;
+    default:
+        break;
+    }
+}
+/**
+ * @brief  解析输入字符串的paramString数据,将数据保存到至该设备结构体下,此处解析commandList
+ * @param  uint8_t *paramString输入的字符串数据,DEVICE_PARAMS *device节点信息
+ * @retval 无
+ */
+void addCommandListParams(char *paramString, DEVICE_PARAMS *device)
+{
+	
+ 	GATEWAY_WRITE_MODBUS_COMMAND *write_modbus_command=pvPortMalloc(sizeof(GATEWAY_WRITE_MODBUS_COMMAND));
+	parseStringField(paramString,"\"identifier\":\"",(char *)&write_modbus_command->keyword);
+
+	write_modbus_command->functionCode=parseIntField(paramString, "\"wFunctionCode\":");
+	write_modbus_command->slaveAddress=parseIntField(paramString, "\"slaveAddress\":");
+	write_modbus_command->registerAddress = parseIntField(paramString, "\"registerAddress\":");
+	write_modbus_command->registerByteNum = parseIntField(paramString, "\"registerByteNum\":");
+	if(device->params->gateway_write_modbus_command == NULL)
+	{
+		device->params->gateway_write_modbus_command=write_modbus_command;
+	}
+	else
+	{
+		GATEWAY_WRITE_MODBUS_COMMAND *current=device->params->gateway_write_modbus_command;
+    while (current->nextParams != NULL)
+    {
+      current = current->nextParams;
+    }
+    current->nextParams = write_modbus_command;		
+	}
+}
+// 提取int数据
+int parseIntField(const char *data, const char *field)
+{
+	int r;
+	char* i;
+	i = strstr(data, field);
+	r = strlen(field);
+    char *ptr = strstr(data, field) + strlen(field);
+    int value;
+    value = strtol(ptr, &ptr, 10);
+    return value;
+}
+
+// 提取string字符串
+void parseStringField(const char *data, const char *field, char *value)
+{
+    char *ptr = strstr(data, field) + strlen(field);
+    sscanf(ptr, "%[^\"],", value);
+}
+
+// 不采用json解析硬解json数据
+void processStringJson(uint8_t *data)
+{
+    GATEWAY_PARAMS *gateway;
+    gateway = get_gateway_config_params();
+    uint8_t *ptr = (uint8_t *)data;
+    parseStringField((char *)&ptr, "\"messageTopic\":\"", (char *)&gateway->messageTopic);
+    parseStringField((char *)&ptr, "\"commandTopic\":\"", (char *)&gateway->commandTopic);
+    gateway->port = parseIntField((char *)&ptr, "\"port\":\"");
+    parseStringField((char *)&ptr, "\"host\":\"", (char *)&gateway->host);
+    parseStringField((char *)&ptr, "\"deviceId\":\"", (char *)&gateway->deviceId);
+    // 解析最外层数据完成,申请空间存储节点信息
+
+    int nodeNum = 1;
+    char *node_index = pvPortMalloc(10);
+    sprintf(node_index, "node_%d", nodeNum);
+    strstr(ptr, node_index); // 将指针指向第一个节点
+    while (*ptr == NULL)
+    {
+
+    }
+    vPortFree(node_index);
+}
+/**
+ * @brief  从输入的input_string中寻找开始到结束位置的字符串数据,并将数据截取出来,传给result;
+ * @param  input_string输入字符串,start_token字符串起始位置,end_token字符串结束位置,result截取出的字符串
+ * @retval 0:没有被截取到的字符串。1:有被截取到的字符串。
+ */
+int extract_substring(const char *input_string, const char *start_token, const char *end_token, char *result)
+{
+    const char *start_ptr = strstr(input_string, start_token);
+
+    if (start_ptr == NULL)
+    {
+        return 0; // 未找到起始标记
+    }
+
+    start_ptr += strlen(start_token); // 移动指针到起始标记之后
+
+    const char *end_ptr = strstr(start_ptr, end_token);
+
+    if (end_ptr == NULL)
+    {
+        // 如果未找到结束标记,将从起始标记开始的字符串一直复制到 \0 结束
+        strcpy(result, start_ptr);
+    }
+    else
+    {
+        // 找到结束标记,计算截取的长度并复制
+        size_t length = end_ptr - start_ptr;
+        strncpy(result, start_ptr, length);
+        result[length] = '\0'; // 添加字符串结束符
+    }
+    return 1;
+}
+
+

+ 1 - 1
app/System/source/gd32_flash.c

@@ -110,4 +110,4 @@ void gd32_flash_test()
 	save_config_params(p);
 	char *t=pvPortMalloc(100);
 	read_data_from_flash(t);
-}
+}

+ 2 - 1
app/System/source/httpclient.c

@@ -100,8 +100,9 @@ int http_clientConnectToServer(char *host, int port, int hostIsIp)
 		timeout = 0;
 		while((addr.addr == 0) && (timeout < 2000)) 
 		{
-			vTaskDelay(100);  
 			timeout += 10;
+			vTaskDelay(100);  
+			
 		}
 		if(timeout >= 2000) 
 		{

+ 1 - 0
app/System/source/log.c

@@ -47,6 +47,7 @@ void LogPrint(logLevel_t logLevel,const char *file, const char *func, const int
 			}
 			udp_send_printf(p);
 			vPortFree(p);
+			p = NULL;
 			udp_log_close();
 			xSemaphoreGive(logMutex);
 		}

+ 48 - 0
app/System/source/sys_http.c

@@ -0,0 +1,48 @@
+#include "httpclient.h"
+#include "string.h"
+#include "stdio.h"
+#include "main.h"
+#include "sys_http.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "log.h"
+#include "gd32_flash.h"
+
+//http配置标志位
+uint8_t load_http_config=0;
+//get请求  http://gpu.ringzle.com:8082/iot/transmit/getTransmitConfig/DT8pd3ac6h 端口8082
+//目前为此处去控制http一次性读入数据大小,应为该处为读入函数
+void http_getDemo(void)
+{
+
+	int datalen;
+	int ret;
+	char *http_data=pvPortMalloc(18 * 1024); // 接收数据上限为19K
+	char *http=pvPortMalloc(50);
+	sprintf(http,"/iot/transmit/getTransmitConfig/%s",gatewayId);
+	ret = http_clientGet("gpu.ringzle.com", http, 8082, 0, http_data, &datalen);
+	if(ret==200) //获取成功
+	{		
+//		save_config_params(http_data);
+		load_http_config=1;
+	}
+	HTTP_PRINTF("%s", (char *)http_data);
+	HTTP_PRINTF("\r\n ret=%d datalen=%d\r\n", ret, datalen);
+	vPortFree(http_data);
+	vPortFree(http);
+	http_data = NULL;
+	http = NULL;
+}
+
+/*
+*********************************************************************************************************
+*	函 数 名: int get_http_config(void)
+*	功能说明: 获取http配置的相关参数
+*	形    参:无
+*	返 回 值: 返回http是否配置 0:没有配置过,1:配置过
+*********************************************************************************************************
+*/
+int get_http_config(void)
+{
+	return load_http_config;
+}

+ 37 - 9
app/System/source/sys_mqtt.c

@@ -10,8 +10,13 @@
 #include "mqtt_config.h"
 #include "mqtt_log.h"
 #include "sys_mqtt.h"
+#include "gateway_message.h"
+#include "data_task.h"
+#include "netconf.h"
 
+int mqtt_connectFlag;
 static void mqtt_publish_task(void *arg);
+
 /*
  *接收并处理mqtt订阅消息
  */
@@ -19,11 +24,14 @@ static void topic1_handler(void *client, message_data_t *msg)
 {
 	(void)client;
 	MQTT_LOG_I("topic: %s\nmessage:%s", msg->topic_name, (char *)msg->message->payload);
+	// json 解析数据
+	
+	write_modbus_data((char*)msg->message->payload);
 }
 /*
  *初始化mqtt连接
  */
-int8_t mqtt_init(mqtt_client_t *client, char *clientId, char *user_name, char *password, char *ip, char *port, uint16_t keepAlive)
+int8_t mqtt_init(mqtt_client_t *client, char *clientId, char *user_name, char *password, char *ip, char* port, uint16_t keepAlive)
 {
 	mqtt_set_client_id(client, clientId);
 	mqtt_set_port(client, port);
@@ -48,13 +56,21 @@ void mqtt_task_creat()
 
 static void mqtt_publish_task(void *arg)
 {
-	mqtt_client_t *client = (mqtt_client_t *)arg;
-	while (1)
+	while(dhcp_done!=1)
 	{
-		LOG_PRINT(LOG_INFO,"mqtt_start");
-//		int rc = mqtt_init(client, "client_id_001", NULL, NULL, "36.134.23.11", "1883", 1000);
 		vTaskDelay(100);
 	}
+	int rc;
+	mqtt_client_t *client = (mqtt_client_t *)arg;
+
+	while (rc < 0)
+	{
+	  rc = mqtt_init(client, "client_id_002", NULL, NULL, "36.134.23.11", "1883", 120);
+		LogPrint(LOG_INFO,__FILE__,__FUNCTION__,__LINE__,"NET TEST");
+		vTaskDelay(1000);	
+	}
+	mqtt_connectFlag = 1;
+//	vPortFree(port);
 	mqtt_subscribe(client, "sub_topic_task", QOS0, topic1_handler);
 	mqtt_message_t msg;
 	memset(&msg, 0, sizeof(msg));
@@ -72,10 +88,18 @@ static void mqtt_publish_task(void *arg)
 				msg.qos = pxMessage->qos;
 				msg.payload = (void *)pxMessage->message;
 				mqtt_publish(client, pxMessage->pub_topic, &msg);
-
+		
+				
+				memset(pxMessage->message,0, pxMessage->pubLength);
+				memset(pxMessage->pub_topic, 0,strlen(pxMessage->pub_topic));
+				memset(pxMessage, 0, sizeof(struct Pub_Queue));
 				vPortFree(pxMessage->message);
 				vPortFree(pxMessage->pub_topic);
 				vPortFree(pxMessage);
+				pxMessage->message = NULL;
+				pxMessage->pub_topic = NULL;
+				pxMessage = NULL;
+				
 			}
 		}
 		vTaskDelay(100);
@@ -89,8 +113,9 @@ static void mqtt_publish_task(void *arg)
  *  函数作用:向队列中写入mqtt上传的消息
  *  TODO:队列满无法写入的情况处理
  */
-void mqtt_publish_data(uint8_t *payload, mqtt_qos_t qos, uint16_t pub_length, char *topic)
+void mqtt_publish_data(char *payload, mqtt_qos_t qos, uint16_t pub_length, char *topic)
 {
+
 	struct Pub_Queue *pxMessage = pvPortMalloc(sizeof(struct Pub_Queue));
 	pxMessage->message = pvPortMalloc(pub_length + 1);
 	memset(pxMessage->message, 0, (pub_length + 1));
@@ -98,7 +123,10 @@ void mqtt_publish_data(uint8_t *payload, mqtt_qos_t qos, uint16_t pub_length, ch
 
 	pxMessage->pub_topic = pvPortMalloc(strlen(topic) + 1);
 	memset(pxMessage->pub_topic, 0, (strlen(topic) + 1));
-	strcpy(pxMessage->pub_topic, topic);
-
+//	strcpy(pxMessage->pub_topic, topic);
+	pxMessage->pub_topic = "/device/DTtest0003";
+	pxMessage->pubLength = pub_length;
+	pxMessage->qos = qos;
 	xQueueSend(xQueue1, (void *)&pxMessage, (TickType_t)0);
+	
 }

+ 10 - 23
app/System/source/tcp_server.c

@@ -14,11 +14,10 @@
 void tcp_server_task(void *pvParameters)
 {
     int ret,sockfd;
-		int recv_size;
     struct sockaddr_in tcpServerSock;
     struct sockaddr_in client_sock;
     tcpServerSock.sin_family = AF_INET;
-		inet_aton("192.168.2.222",&(tcpServerSock.sin_addr));
+		inet_aton("192.168.2.228",&(tcpServerSock.sin_addr));
 //    tcpServerSock.sin_addr.s_addr = htonl(IPADDR_ANY);
     tcpServerSock.sin_port = htons(8080);
 tcp_server_begin:
@@ -41,29 +40,17 @@ tcp_server_begin:
         sockfd = -1;
         goto tcp_server_begin;
     }
-		socklen_t len = sizeof(client_sock);
-    int client_socket = accept(sockfd, (struct sockaddr*)&client_sock,&len);
-		if (client_socket<0)
-    {
-      printf("error");
-    }
-		LOG_PRINT(LOG_INFO,"上位机连接成功");
+		
     while (1)
     {
 				vTaskDelay(1000);
-				char *cmd=pvPortMalloc(1024);
-				recv_size=recv(client_socket,cmd,1024,0);
-				if(recv_size>0)
-				{
-					LOG_PRINT(LOG_INFO,"服务端recv:%s",cmd);					
-				}
-				else if(recv_size==0)
-				{
-					lwip_close(client_socket);
-					vPortFree(cmd);
-					LOG_PRINT(LOG_WARN,"上位机断连,重新等待连接");
-					client_socket= accept(sockfd, (struct sockaddr*)&client_sock,&len);
-				}
+        socklen_t len = sizeof(client_sock);
+        int client_socket = accept(sockfd, (struct sockaddr*)&client_sock,&len);
+				LogPrint(LOG_INFO,__FILE__,__FUNCTION__,__LINE__,"上位机成功连接%s");
+        if (client_socket<0)
+        {
+            printf("error");
+        }
     }
     
 }
@@ -75,5 +62,5 @@ tcp_server_begin:
 */
 void tcp_server_init(void)
 {
-    xTaskCreate(tcp_server_task, "TCP_CLIENT", DEFAULT_THREAD_STACKSIZE, NULL, 4, NULL);
+    xTaskCreate(tcp_server_task, "TCP_CLIENT", DEFAULT_THREAD_STACKSIZE, NULL, 1, NULL);
 }

+ 1 - 1
app/System/source/udp.c

@@ -160,7 +160,7 @@ static void udp_task(void *arg)
 volatile int8_t sockfd=-1;
 #define UDP_LOCAL_PORT 12345
 #define UDP_REMOTE_PORT 54321
-#define SERCER_IP_ADDRESS "192.168.2.22"       //½ÓÊÕ·þÎñÆ÷ip
+#define SERCER_IP_ADDRESS "192.168.2.211"       //½ÓÊÕ·þÎñÆ÷ip
 struct sockaddr_in remote_addr;
 int udp_log_start()
 {

+ 3 - 3
app/USR/include/FreeRTOSConfig.h

@@ -82,7 +82,7 @@ extern uint32_t SystemCoreClock;
 #define configTICK_RATE_HZ                            ( ( TickType_t ) 1000 )
 #define configMAX_PRIORITIES                          ( 6 )
 #define configMINIMAL_STACK_SIZE                      ( ( unsigned short ) 128 )
-#define configTOTAL_HEAP_SIZE                         ( ( size_t ) ( 45 * 1024 ) )
+#define configTOTAL_HEAP_SIZE                         ( ( size_t ) ( 40 * 1024 ) )
 #define configMAX_TASK_NAME_LEN                       ( 16 )
 #define configUSE_16_BIT_TICKS                        0
 #define configIDLE_SHOULD_YIELD                       1
@@ -152,8 +152,8 @@ priority than this! (higher priorities are lower numeric values. */
 
 
 /* normal assert() semantics without relying on the provision of an assert.h header file */
-#define configASSERT( x )                              if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } 
-
+//#define configASSERT( x )                              if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } 
+#define configASSERT(x)  ((void)0)
 /* map the FreeRTOS port interrupt handlers to CMSIS standard names */
 #define vPortSVCHandler SVC_Handler
 #define xPortPendSVHandler PendSV_Handler

+ 3 - 0
app/USR/include/main.h

@@ -12,10 +12,13 @@
 #ifndef MAIN_H
 #define MAIN_H
 
+#define USE_DHCP
+
 #include "gd32f30x.h"
 #include "stdint.h"
 #include "hd_eth.h"
 #include "FreeRTOS.h"
 //SemaphoreHandle_t logMutex;
+extern char  gatewayId[11];
 
 #endif /* MAIN_H */

+ 32 - 13
app/USR/source/main.c

@@ -53,14 +53,21 @@ OF SUCH DAMAGE.
 #include "tcp_server.h"
 #include "log.h"
 #include "gd32_flash.h"
+#include "timer.h"
+
+#include "sys_http.h"
+#include "data_task.h"
+#include "mmodbus.h"
+
 /*
 *freertos优先级管理
 *管理启动流程任务 init_task        	优先级 1
 *freertos时间任务 prvTimerTask     	优先级 2
-*上位机交互任务   tcp_server        优先级 4
+*上位机交互任务  	tcp_server        优先级 1
 *可能会开启的任务 dhcp_task        	优先级 4
 *mqtt通信任务			mqtt_publish_task 优先级 4
 *以太网输入任务   ethernetif_input 	优先级 5
+*数据处理任务     data_task         优先级 3
 */
 #define INIT_TASK_PRIO   ( tskIDLE_PRIORITY + 1 )
 #define DHCP_TASK_PRIO   ( tskIDLE_PRIORITY + 4 )
@@ -71,8 +78,7 @@ OF SUCH DAMAGE.
  
 void led_task(void * pvParameters); 
 void init_task(void * pvParameters);
-
-
+char  gatewayId[11];
 
 /*!
     \brief      main function
@@ -82,17 +88,20 @@ void init_task(void * pvParameters);
 */
 int main(void)
 {
+		sprintf(gatewayId,"DTtest0001");//DT8pd3ac6h  DTbma5ac6h  DTtest0001
 	   /* configure 4 bits pre-emption priority */
     nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
 		gd_485_DE_pin_init();
 		config_485_port(COM_485,115200,8,1,0);
-		gd_485_DE_tx();
+		
+		timer5_init();
+
     /* init task */
-    xTaskCreate(init_task, "INIT",1024, NULL, INIT_TASK_PRIO, NULL);
+    xTaskCreate(init_task, "INIT",256, NULL, INIT_TASK_PRIO, NULL);
     /* start scheduler */
     vTaskStartScheduler();
     while(1)
-		{ 	
+		{
 			
     }
 		
@@ -104,24 +113,30 @@ int main(void)
     \param[out] none
     \retval     none
 */
- 
+int fttime1, fttime2;
 void init_task(void * pvParameters)
 {
-	gd32_flash_test();
+//		gd32_flash_test();
     /* configure ethernet (GPIOs, clocks, MAC, DMA) */ 
     enet_system_setup();
-		log_init();
     /* initilaize the LwIP stack */
-    lwip_stack_init();
+		lwip_stack_init();
+		log_init();
     /* initilaize the tcp server: telnet 8000 */
-
+//    hello_gigadevice_init();
+    /* initilaize the tcp client: echo 1026 */
+//    tcp_client_init();
+    /* initilaize the udp: echo 1025 */
 	 tcp_server_init();
-#ifdef USE_DHCP	
+#ifdef USE_DHCP
     /* start DHCP client */
     xTaskCreate(dhcp_task, "DHCP", 512, NULL, DHCP_TASK_PRIO, NULL);
 #endif /* USE_DHCP */
+		
     /* start toogle LED task every 250ms */
 //    xTaskCreate(led_task, "LED", 512, NULL, LED_TASK_PRIO, NULL);
+		http_getDemo();
+		xTaskCreate(data_task, "DATA",1024, NULL, DATA_TASK_PRIO, NULL);
 		mqtt_task_creat();
     for( ;; ){
         vTaskDelete(NULL);
@@ -150,7 +165,11 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName )
 {
 	LogPrint(LOG_ERROR,__FILE__,__FUNCTION__,__LINE__,"task :%s 栈溢出\r\n",pcTaskName);
 }
+void vApplicationHeapOverflowHook(TaskHandle_t xTask, char *pcTaskName )
+{
+	LogPrint(LOG_ERROR,__FILE__,__FUNCTION__,__LINE__,"task :%s 堆溢出\r\n",pcTaskName);
+}
 void vApplicationMallocFailedHook()
 {
 		LogPrint(LOG_ERROR,__FILE__,__FUNCTION__,__LINE__,"malloc error");
-}
+}

+ 1 - 1
app/USR/source/tcp_client.c

@@ -153,7 +153,7 @@ static void tcp_client_task(void *arg)
 
 #if LWIP_SOCKET
 #include "lwip/sockets.h"
-#define SERVER_IP_ADDRESS "192.168.2.22"
+#define SERVER_IP_ADDRESS "192.168.2.210"
 #define SERVER_PORT 8080
 #define MESSAGE "hello, world"
 

+ 47 - 0
app/dlt/inc/dlt645.h

@@ -0,0 +1,47 @@
+#ifndef _DLT645_H
+#define _DLT645_H
+
+#include <stdint.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#define DL645_MAX_READ_LEN 200 //读数据的最大数据长度
+#define DL645_MAX_WRITE_LEN 50 //写数据的最大数据长度
+
+// port setting
+#define DLT645_DEFAULT_RESPONSE_TIMEOUT 500 //500ms
+#define MAX_DEVICE_NAME_LEN 10              //最大设备名长度
+
+#define dlt_malloc malloc
+#define dlt_free free
+#define gettick()                           ( xTaskGetTickCount() )
+//DLT645 环境结构体
+typedef struct dlt645
+{
+    uint8_t addr[6];    //从机地址
+    uint8_t debug;      //调试标志
+    int (*write)(struct dlt645 *ctx, uint8_t *buf, uint16_t len);     //底层写函数
+    int (*read) (struct dlt645 *ctx, uint8_t *msg, uint16_t len);     //底层读函数
+    void *port_data;                                            //移植层拓展接口
+} dlt645_t;
+
+typedef enum
+{
+    DLT645_2007 = 1,
+    DLT645_1997
+} dlt645_protocal;
+
+//设置从机地址
+extern void dlt645_set_addr(dlt645_t *ctx, uint8_t *addr);
+//设置调试开关
+extern int dlt645_set_debug(dlt645_t *ctx, int flag);
+//数据采集
+extern int dlt645_read_data(dlt645_t *ctx, uint32_t code, uint8_t *read_data, dlt645_protocal protocal);
+//十进制转BCD码(32位)
+extern uint32_t dec_to_bcd(uint32_t val);
+//字符串转BCD形式
+extern int str_to_bcd(char *str, uint8_t *bcd_store_address, uint16_t bcd_len);
+
+extern void dlt645_init(uint32_t timeout);
+extern void dlt_callback(void);
+
+#endif

+ 11 - 0
app/dlt/inc/dlt645_1997.h

@@ -0,0 +1,11 @@
+#ifndef __DLT645_1997_H
+#define __DLT645_1997_H
+
+#include "dlt645.h"
+
+//基于 DLT645 2007 协议读取数据
+int dlt645_1997_read_data(dlt645_t *ctx, uint32_t code, uint8_t *read_data);
+//基于 DLT645 2007 协议校验数据
+int dlt645_1997_recv_check(uint8_t *msg, int len, uint8_t *addr, uint32_t code);
+
+#endif /* __DLT645_1997_H */

+ 53 - 0
app/dlt/inc/dlt645_1997_private.h

@@ -0,0 +1,53 @@
+#ifndef __DLT645_1997_PRIVATE_H
+#define __DLT645_1997_PRIVATE_H
+
+#define DL645_1997_RD_CMD_LEN 14 //读取数据命令的长度
+
+//功能码
+#define C_1997_CODE_BRC 0x08    //广播校时
+#define C_1997_CODE_RD 0x01     //读数据
+#define C_1997_CODE_RDM 0x02    //读后续数据
+#define C_1997_CODE_WR 0x04     //写数据
+#define C_1997_CODE_WRA 0x0A    //写设备地址
+#define C_1997_CODE_BR 0x0C     //更改通信速率
+#define C_1997_CODE_PD 0x0F     //修改密码
+#define C_1997_CODE_XL 0x10     //最大需量清零
+#define C_1997_CEODE_RR 0x03    //重读数据
+
+
+#define ERR_1997_RATE 0x40  //费率数超
+#define ERR_1997_DAY 0x20   //日时段数超
+#define ERR_1997_YEAR 0x10  //年时区数超
+#define ERR_1997_BR 0x08    //通信速率不能更改
+#define ERR_1997_PD 0x04    //密码错误/未授权
+#define ERR_1997_DATA 0x02  //无请求数据
+#define ERR_1997_OTHER 0x01 //其他错误
+
+// DLT645 1997 数据标识
+#define DIC_B611 0xB611 //A相电压
+#define DIC_B612 0xB612 //B相电压
+#define DIC_B613 0xB613 //C相电压
+#define DIC_B691 0xB691 //AB线电压
+#define DIC_B692 0xB692 //BC线电压
+#define DIC_B693 0xB693 //CA线电压
+
+#define DIC_B621 0xB621 //A相电流
+#define DIC_B622 0xB622 //B相电流
+#define DIC_B623 0xB623 //C相电流
+
+#define DIC_B630 0xB630 //总有功功率
+#define DIC_B631 0xB631 //A相有功功率
+#define DIC_B632 0xB632 //B相有功功率
+#define DIC_B633 0xB633 //C相有功功率
+
+#define DIC_B640 0xB640 //总无功功率
+#define DIC_B641 0xB641 //A相无功功率
+#define DIC_B642 0xB642 //B相无功功率
+#define DIC_B643 0xB643 //C相无功功率
+
+#define DIC_B660 0xB660 //总视在功率
+#define DIC_B661 0xB661 //A相视在功率
+#define DIC_B662 0xB662 //B相视在功率
+#define DIC_B663 0xB663 //C相视在功率
+
+#endif /* __DLT645_1997_PRIVATE_H */

+ 11 - 0
app/dlt/inc/dlt645_2007.h

@@ -0,0 +1,11 @@
+#ifndef __DLT645_2007_H
+#define __DLT645_2007_H
+
+#include "dlt645.h"
+
+//基于 DLT645 2007 协议读取数据
+int dlt645_2007_read_data(dlt645_t *ctx, uint32_t code, uint8_t *read_data);
+//基于 DLT645 2007 协议校验数据
+int dlt645_2007_recv_check(uint8_t *msg, int len, uint8_t *addr, uint32_t code);
+
+#endif /* __DLT645_2007_H */

+ 128 - 0
app/dlt/inc/dlt645_2007_private.h

@@ -0,0 +1,128 @@
+#ifndef __DLT645_2007_PRIVATE_H
+#define __DLT645_2007_PRIVATE_H
+
+
+#define DL645_2007_RD_CMD_LEN 16 //读取数据命令的长度
+
+//功能码
+#define C_2007_CODE_BRC 0x08    //广播校时
+#define C_2007_CODE_RD 0X11     //读数据
+#define C_2007_CODE_RDM 0x12    //读后续数据
+#define C_2007_CODE_RDA 0x13    //读通信地址
+#define C_2007_CODE_WR 0x14     //写数据
+#define C_2007_CODE_WRA 0x15    //写通信地址
+#define C_2007_CODE_DJ 0x16     //冻结
+#define C_2007_CODE_BR 0x17     //更改通信速率
+#define C_2007_CODE_PD 0x18     //修改密码
+#define C_2007_CODE_XL 0x19     //最大需量清零
+#define C_2007_CODE_DB 0x1a     //电表清零
+#define C_2007_CODE_MSG 0x1b    //事件清零
+
+
+#define ERR_2007_RATE 0x40  //费率数超
+#define ERR_2007_DAY 0x20   //日时段数超
+#define ERR_2007_YEAR 0x10  //年时区数超
+#define ERR_2007_BR 0x08    //通信速率不能更改
+#define ERR_2007_PD 0x04    //密码错误/未授权
+#define ERR_2007_DATA 0x02  //无请求数据
+#define ERR_2007_OTHER 0x01 //其他错误
+
+
+
+
+#define DIC_0 0x0         //组合有功总电能
+#define DIC_100 0x100     //组合有功费率1电能
+#define DIC_200 0x200     //组合有功费率2电能
+#define DIC_300 0x300     //组合有功费率3电能
+#define DIC_400 0x400     //组合有功费率4电能
+#define DIC_10000 0x10000 //正向有功总电能
+#define DIC_10001 0x10001 //(上1结算日 即上月)正向有功总电能
+#define DIC_10100 0x10100 //正向有功费率1电能
+#define DIC_10002 0x10002 //(上2结算日 即上月)正向有功总电能
+
+#define DIC_10200 0x10200 //正向有功费率2电能
+#define DIC_10300 0x10300 //正向有功费率3电能
+#define DIC_10400 0x10400 //正向有功费率4电能
+#define DIC_20000 0x20000 //反向有功总电能
+#define DIC_20100 0x20100 //反向有功费率1电能
+#define DIC_20200 0x20200 //反向有功费率2电能
+#define DIC_20300 0x20300 //反向有功费率3电能
+#define DIC_20400 0x20400 //反向有功费率4电能
+#define DIC_30000 0x30000 //组合无功1总电能
+#define DIC_40000 0x40000 //组合无功2总电能
+#define DIC_50000 0x50000 //第一象限无功电能
+#define DIC_60000 0x60000 //第二象限无功电能
+#define DIC_70000 0x70000 //第三象限无功电能
+#define DIC_80000 0x80000 //第四象限无功电能
+#define DIC_90000 0x90000 //正向视在总电能
+
+#define DIC_1010000 0X01010000//正向正向有功总最大需量及发生时间
+#define DIC_1010100 0x01010100//正向有功费率 1 最大需量及发生时间
+
+
+#define DIC_1020000 0x01020000//反向有功总最大需量及发生时间
+#define DIC_1010001 0x01010001//正向有功总最大需量及发生时间
+#define DIC_1020001 0X01020001//反向有功总最大需量及发生时间
+
+#define DIC_201FF00 0x201FF00	//电压数据块
+#define DIC_2010100 0x2010100 //A相电压
+#define DIC_2010200 0x2010200 //B相电压
+#define DIC_2010300 0x2010300 //C相电压
+#define DIC_2020100 0x2020100 //A相电流
+#define DIC_2020200 0x2020200 //B相电流
+#define DIC_2020300 0x2020300 //C相电流
+#define DIC_2030000 0x2030000 //总有功功率
+#define DIC_2030100 0x2030100 //A相有功功率
+#define DIC_2030200 0x2030200 //B相有功功率
+#define DIC_2030300 0x2030300 //C相有功功率
+
+#define DIC_2040000 0x2040000 //总无功功率
+#define DIC_2040100 0x2040100 //A相无功功率
+#define DIC_2040200 0x2040200 //B相无功功率
+#define DIC_2040300 0x2040300 //C相无功功率
+#define DIC_2050000 0x2050000 //总视在功率
+#define DIC_2050100 0x2050100 //A相视在功率
+#define DIC_2050200 0x2050200 //B相视在功率
+#define DIC_2050300 0x2050300 //C相视在功率
+#define DIC_2060000 0x2060000 //总功率因素
+#define DIC_2060100 0x2060100 //A相功率因素
+#define DIC_2060200 0x2060200 //B相功率因素
+#define DIC_2060300 0x2060300 //C相功率因素
+#define DIC_20C0100 0x20C0100 //AB线电压
+#define DIC_20C0200 0x20C0200 //BC线电压
+#define DIC_20C0300 0x20C0300 //CA线电压
+#define DIC_2800002 0x2800002 //频率
+#define DIC_2800007 0x2800007//表内温度
+#define DIC_4000101 0x4000101 //年月日星期
+#define DIC_4000102 0x4000102 //时分秒
+#define DIC_5060001 0x5060001 //上一次日冻结时间
+#define DIC_5060101 0x5060101 //上一次日冻结正向有功电能
+
+
+
+#define DIC_30C0000 0x30C0000 //过流总次数,总时间
+#define DIC_30C0101 0x30C0101 //上一次A相过流记录
+
+#define DIC_3300100 0x3300100 //电表清零总次数
+#define DIC_3300101 0x3300101 //电表清零记录
+
+#define DIC_4000501 0x4000501
+#define DIC_4000502 0x4000502
+#define DIC_4000503 0x4000503
+#define DIC_4000504 0x4000504
+#define DIC_4000505 0x4000505
+#define DIC_4000506 0x4000506
+#define DIC_4000507 0x4000507
+
+#define DIC_4000403 0x4000403 //资产管理编码
+
+#define DIC_4000701 0x4000701 //信号强度
+
+#define DIC_4000702 0x4000702 //版本号
+
+
+
+#define DIC_7000001 0x7000001 //master_api_key
+#define DIC_7000002 0x7000002 //device_id
+
+#endif /* __DLT645_2007_PRIVATE_H */

+ 56 - 0
app/dlt/inc/dlt645_private.h

@@ -0,0 +1,56 @@
+#ifndef _DLT645_PRIVATE_H
+#define _DLT645_PRIVATE_H
+
+#include "dlt645.h"
+
+#ifdef DLT645_DEBUG
+#define DLT645_LOG kprintf
+#else
+#define DLT645_LOG(...)
+#endif
+
+#define DL645_START_CODE 0x68
+#define DL645_STOP_CODE 0x16
+
+#define DL645_PREMBLE_ENABLE 0 //前导码使能标记
+#define DL645_PREMBLE 0xFE     //前导码
+
+#define DL645_ADDR_LEN 6    //设备地址长度
+#define DL645_CONTROL_POS 8 //控制码位置
+#define DL645_LEN_POS 9     //长度位置
+#define DL645_DATA_POS 10   //数据位置
+#define DL645_WR_LEN 50     //写入数据命令的长度
+#define DL645_RESP_LEN 60   //读取数据命令的长度
+
+#define C_TD_MASK 0x80      //主从标志位
+#define C_TD_POS 7          //主从标志位比特位
+#define C_TD_MASTER 0       //主站发出的命令帧
+#define C_TD_SLAVE 1        //从站发出的应答帧
+
+#define C_ACK_MASK 0x40     //从站是否正确应答标志位
+#define C_ACK_POS 6         //从站应答标志位比特位
+#define C_ACK_OK 0          //从站应答正确
+#define C_ACK_ERR 1         //从站应答错误
+
+#define C_FU_MASK 0x20      //是否有后续帧标志位
+#define C_FU_POS 5          //后续帧标志位比特位
+#define C_FU_NONE 0         //无后续帧
+#define C_FU_EXT 1          //有后续帧
+
+#define C_CODE_MASK 0x1F    //功能码标志位
+
+
+
+//645 公共校验
+extern int dlt645_common_check(uint8_t *msg, int len, uint8_t *addr);
+//645 和校验
+extern int _crc(uint8_t *msg, int len);
+//645 调用底层接口接收数据
+extern int dlt645_receive_msg(dlt645_t *ctx, uint8_t *msg, uint16_t len, uint32_t code, dlt645_protocal protocal);
+//645 调用底层接口发送
+extern int dlt645_send_msg(dlt645_t *ctx, uint8_t *msg, int len);
+//将接收到的dlt645数据包中的数据转化为整数
+extern int data_package_translate_to_int(uint8_t *read_data, uint16_t len);
+//根据数据格式将645协议读取的数据转换为真实数据并存储
+extern int dlt645_data_parse_by_format_to_float(uint8_t *read_data, uint16_t read_len, const char *data_format, uint8_t *store_address);
+#endif

+ 132 - 0
app/dlt/port/dlt645_port.c

@@ -0,0 +1,132 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645_port.c
+ Description:   DLT645 移植&使用例程文件
+ History:
+ 1. Version:
+	Date:       2019-09-19
+	Author:     wangjunjie
+	Modify:
+*************************************************/
+#include "dlt645.h"
+#include "gd32f30x.h"
+#include "delay.h"
+#include "usart.h"
+#include "string.h"
+
+#define DLT_RXSIZE 200
+
+// DLT645采集使用的串口名
+#define DLT645_USART COM_485
+#define DLT645_CTRL_GPIO DE485_GPIO_PORT
+#define DLT645_CTRL_PIN DE485_PIN
+
+// DL/T 645硬件拓展结构体
+typedef struct
+{
+	uint8_t dlt645_Tx; // 用于串口接收的状态
+	uint32_t timeout;  //
+	uint8_t rxBuf[DLT_RXSIZE];
+	uint8_t done;
+	uint8_t index;
+} dlt645_port_t;
+
+static dlt645_port_t dlt645_port;
+
+// dlt645 环境结构体
+dlt645_t dlt645;
+
+void dlt_callback()
+{
+	if(RESET!=usart_flag_get(DLT645_USART,USART_FLAG_RBNE))
+	{
+		if (dlt645_port.index < DLT_RXSIZE - 1)
+		{
+				dlt645_port.rxBuf[dlt645_port.index] = usart_data_receive(DLT645_USART);
+				dlt645_port.index++;
+			}
+		else
+		{
+			usart_data_receive(DLT645_USART);
+		}
+	}
+	if((dlt645_port.index > 0) && RESET != usart_flag_get(DLT645_USART, USART_FLAG_IDLE))
+	{                           
+		usart_interrupt_disable(DLT645_USART, USART_INT_IDLE);
+		dlt645_port.done = 1;
+	}
+}
+/**
+ * Name:    dlt645_hw_read
+ * Brief:   dlt645 硬件层接收数据
+ * Input:
+ *  @ctx:   645运行环境
+ *  @msg:   接收数据存放地址
+ *  @len:   数据最大接收长度
+ * Output:  读取数据的长度
+ */
+static int dlt645_hw_read(dlt645_t *ctx, uint8_t *msg, uint16_t len)
+{
+	int dataLength = 0;
+	int startTime = gettick();
+	while (1)
+	{
+		if (gettick() - startTime > dlt645_port.timeout )
+			return 0;
+		if (dlt645_port.done == 1)
+		{
+			dataLength = dlt645_port.index;
+			memcpy(msg, &(dlt645_port.rxBuf[4]), len-4);
+			dataLength = dlt645_port.index-4;
+			return dataLength;
+		}
+	}
+}
+
+/**
+ * Name:    dlt645_hw_write
+ * Brief:   dlt645 硬件层发送数据
+ * Input:
+ *  @ctx:   645运行环境
+ *  @buf:   待发送数据
+ *  @len:   发送长度
+ * Output:  实际发送的字节数,错误返回-1
+ */
+static int dlt645_hw_write(dlt645_t *ctx, uint8_t *buf, uint16_t len)
+{
+	memset(dlt645_port.rxBuf, 0, DLT_RXSIZE);
+	delay_ms(10);
+	gpio_bit_write(DLT645_CTRL_GPIO,DLT645_CTRL_PIN,1);
+	for (uint16_t i = 0; i <=len; i++)
+	{
+		usart_data_transmit(USART0,buf[i]);
+		while (usart_flag_get(DLT645_USART, USART_FLAG_TBE) == RESET);	
+	}
+	gpio_bit_write(DLT645_CTRL_GPIO,DLT645_CTRL_PIN,0);
+	dlt645_port.index = 0;
+	dlt645_port.done = 0;
+	return len;
+}
+
+
+
+
+
+
+void dlt645_init(uint32_t timeout)
+{
+	gpio_bit_write(DLT645_CTRL_GPIO,DLT645_CTRL_PIN,1);
+	dlt645_port.timeout = timeout;
+	dlt645_port.dlt645_Tx = 0;
+	dlt645_port.index = 0;
+}
+
+// 645结构体注册
+static dlt645_t dlt645 = {
+	{0},
+	0,
+	dlt645_hw_write,
+	dlt645_hw_read,
+	(void *)&dlt645_port
+};

+ 10 - 0
app/dlt/port/dlt645_port.h

@@ -0,0 +1,10 @@
+#ifndef __DLT645_PORT_H
+#define __DLT645_PORT_H
+#include "dlt645.h"
+
+//对外提供环境声明
+extern dlt645_t dlt645;
+//645采集硬件层初始化
+int dlt645_port_init(void);
+
+#endif

+ 131 - 0
app/dlt/src/dlt645.c

@@ -0,0 +1,131 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645.c
+ Description:   
+ History:
+ 1. Version:    
+    Date:       2019-09-20
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include "dlt645_private.h"
+#include "dlt645_1997.h"
+#include "dlt645_2007.h"
+#include "string.h"
+
+/**
+ * Name:    dlt645_receive_msg
+ * Brief:   645协议调用底层接收数据
+ * Input:
+ *  @ctx:       645环境句柄
+ *  @msg:       数据包存储地址
+ *  @len:       最大接收长度
+ *  @addr:      从站地址
+ *  @code:      数据标识   
+ *  @protocal:  645协议类型  
+ * Output:  接收成功:0,接收失败:-1
+ */
+int dlt645_receive_msg(dlt645_t *ctx, uint8_t *msg, uint16_t len, uint32_t code, dlt645_protocal protocal)
+{
+    int msg_len = ctx->read(ctx, msg, len);
+	
+    if (protocal == DLT645_1997)
+    {
+        return dlt645_1997_recv_check(msg, msg_len, ctx->addr, code);
+    }
+    else if (protocal == DLT645_2007)
+    {
+        return dlt645_2007_recv_check(msg, msg_len, ctx->addr, code);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+/**
+ * Name:    dlt645_send_msg
+ * Brief:   645协议调用底层发送数据
+ * Input:
+ *  @ctx:       645环境句柄
+ *  @msg:       发送的数据首地址
+ *  @len:       发送长度 
+ * Output:  实际发送的字节数,错误返回-1
+ */
+int dlt645_send_msg(dlt645_t *ctx, uint8_t *msg, int len)
+{
+    msg[0] = DL645_START_CODE;
+    msg[DL645_ADDR_LEN + 1] = DL645_START_CODE;
+    msg[len - 1] = DL645_STOP_CODE;
+    msg[len - 2] = _crc(msg, len - 2);
+
+    return ctx->write(ctx, msg, len);
+}
+
+/**
+ * Name:    dlt645_set_addr
+ * Brief:   设置从站地址
+ * Input:
+ *  @ctx:       645环境句柄
+ *  @addr:      从站地址
+ * Output:  None
+ */
+void dlt645_set_addr(dlt645_t *ctx, uint8_t *addr)
+{
+    uint8_t addr_temp[6];
+    memset(addr_temp, 0, 6);
+
+    //转换字节序
+    for (int i = 0; i < 6; i++)
+    {
+        addr_temp[5 - i] = addr[i];
+    }
+    memcpy(ctx->addr, addr_temp, DL645_ADDR_LEN);
+}
+
+/**
+ * Name:    dlt645_set_debug
+ * Brief:   设置调试模式
+ * Input:
+ *  @ctx:       645环境句柄
+ *  @flag:      调试标志
+ * Output:  None
+ */
+int dlt645_set_debug(dlt645_t *ctx, int flag)
+{
+    ctx->debug = flag;
+    return 0;
+}
+
+/**
+ * Name:    dlt645_read_data(用户调用)
+ * Brief:   根据645协议类型读取数据
+ * Input:
+ *  @ctx:           645环境句柄
+ *  @addr:          从站地址
+ *  @code:          标识符
+ *  @read_data:     读取数据存储地址
+ *  @protocal:      协议类型
+ * Output:  成功返回数据长度,失败返回-1
+ */
+int dlt645_read_data(dlt645_t *ctx,
+                     uint32_t code,
+                     uint8_t *read_data,
+                     dlt645_protocal protocal)
+{
+    int rs = -1;
+    switch (protocal)
+    {
+    case DLT645_1997:
+        rs = dlt645_1997_read_data(ctx, code, read_data);
+        break;
+    case DLT645_2007:
+        rs = dlt645_2007_read_data(ctx, code, read_data);
+        break;
+    default:
+        DLT645_LOG("unrecognized protocal!\r\n");
+        break;
+    }
+    return rs;
+}

+ 141 - 0
app/dlt/src/dlt645_1997.c

@@ -0,0 +1,141 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645_1997.c
+ Description:   DLT645 1997版本
+ History:
+ 1. Version:    
+    Date:       2019-09-19
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include "dlt645_private.h"
+#include "dlt645_1997_private.h"
+#include "string.h"
+
+/**
+ * Name:    dlt645_1997_recv_check
+ * Brief:   DLT645-1997 数据校验
+ * Input:
+ *  @msg:   校验数据包
+ *  @len:   数据包长度
+ *  @addr:  从站地址
+ *  @code:  操作码
+ * Output:  校验成功:0 ,失败 -1
+ */
+int dlt645_1997_recv_check(uint8_t *msg, int len, uint8_t* addr, uint32_t code)
+{
+    if (dlt645_common_check(msg, len, addr) < 0)
+    {
+        return -1;
+    }
+    if (msg[DL645_CONTROL_POS] == 0x84)
+        return 0;
+
+    uint8_t *code_buf = (uint8_t *)&code;
+
+    for (uint8_t i = 0; i < 2; i++)
+    {
+        code_buf[i] += 0x33;
+    }
+
+    if (*((uint16_t *)(msg + DL645_DATA_POS)) != code)
+        return -1;
+
+    return 0;
+}
+
+/**
+ * Name:    dlt645_1997_parsing_data
+ * Brief:   DLT645-1997 数据包解析
+ * Input:
+ *  @code:          标识符
+ *  @read_data:     数据包指针
+ *  @len:           数据包长度
+ *  @real_val:      数据存储地址
+ * Output:  数据包长度
+ */
+static int dlt645_1997_parsing_data(uint32_t code, uint8_t *read_data, uint16_t len, uint8_t *real_val)
+{
+    switch (code)
+    {
+    case DIC_B611:
+    case DIC_B612:
+    case DIC_B613:
+    case DIC_B691:
+    case DIC_B692:
+    case DIC_B693:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 2, "XXX", real_val);
+        break;
+    }
+    case DIC_B621:
+    case DIC_B622:
+    case DIC_B623:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 2, "XX.XX", real_val);
+        break;
+    }
+    case DIC_B630:
+    case DIC_B631:
+    case DIC_B632:
+    case DIC_B633:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 3, "XX.XXXX", real_val);
+        break;
+    }
+    default:
+    {
+        for (uint16_t i = 0; i < len; i++)
+        {
+            real_val[i] = ((read_data[i] - 0x33) & 0x0f) + ((read_data[i] - 0x33) >> 4) * 10;
+        }
+        break;
+    }
+    }
+    return len;
+}
+
+/**
+ * Name:    dlt645_1997_read_data
+ * Brief:   DLT645-1997 数据读取
+ * Input:
+ *  @ctx:           645句柄
+ *  @addr:          从站地址
+ *  @code:          数据标识
+ *  @read_data:     数据存储地址
+ * Output:  成功返回数据长度,失败返回-1
+ */
+int dlt645_1997_read_data(dlt645_t *ctx,
+                          uint32_t code,
+                          uint8_t *read_data)
+{
+    uint8_t send_buf[DL645_1997_RD_CMD_LEN];
+    uint8_t read_buf[DL645_RESP_LEN];
+
+    memset(read_buf, 0, sizeof(read_buf));
+    memset(send_buf, 0, sizeof(send_buf));
+
+    memcpy(send_buf + 1, ctx->addr, DL645_ADDR_LEN);
+    send_buf[DL645_CONTROL_POS] = C_1997_CODE_RD;
+    send_buf[DL645_LEN_POS] = 2;
+
+    uint8_t send_code[2] = {0};
+    send_code[0] = (code & 0xff) + 0x33;
+    send_code[1] = ((code >> 8) & 0xff) + 0x33;
+    memcpy(send_buf + DL645_DATA_POS, send_code, 2);
+
+    if (dlt645_send_msg(ctx, send_buf, DL645_1997_RD_CMD_LEN) < 0)
+    {
+        DLT645_LOG("send data error!\n");
+        return -1;
+    }
+
+    if (dlt645_receive_msg(ctx, read_buf, DL645_RESP_LEN, code, DLT645_1997) < 0)
+    {
+        DLT645_LOG("receive msg error!\n");
+        return -1;
+    }
+
+    return dlt645_1997_parsing_data(code, read_buf + DL645_DATA_POS + 2, read_buf[DL645_LEN_POS] - 2, read_data);
+}

+ 279 - 0
app/dlt/src/dlt645_2007.c

@@ -0,0 +1,279 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645_2007.c
+ Description:   DLT645 2007版本
+ History:
+ 1. Version:
+    Date:       2019-09-19
+    Author:     wangjunjie
+    Modify:
+*************************************************/
+#include "dlt645_private.h"
+#include "dlt645_2007_private.h"
+#include "string.h"
+
+/**
+ * Name:    dlt645_2007_recv_check
+ * Brief:   DLT645-2007 数据校验
+ * Input:
+ *  @msg:   校验数据包
+ *  @len:   数据包长度
+ *  @addr:  从站地址
+ *  @code:  操作码
+ * Output:  None
+ */
+int dlt645_2007_recv_check(uint8_t *msg, int len, uint8_t *addr, uint32_t code)
+{
+    if (dlt645_common_check(msg, len, addr) < 0)
+    {
+        return -1;
+    }
+    if (msg[DL645_CONTROL_POS] == 0x94)
+        return 0;
+
+    uint8_t *code_buf = (uint8_t *)&code;
+
+    for (uint8_t i = 0; i < 4; i++)
+    {
+        code_buf[i] += 0x33;
+    }
+
+    if (*((uint32_t *)(msg + DL645_DATA_POS)) != code)
+        return -1;
+
+    return 0;
+}
+
+/**
+ * Name:    dlt645_2007_parsing_data
+ * Brief:   DLT645-2007 数据包解析
+ * Input:
+ *  @code:          标识符
+ *  @read_data:     数据包指针
+ *  @len:           数据包长度
+ *  @real_val:      数据存储地址
+ * Output:  数据包长度
+ */
+int dlt645_2007_parsing_data(uint32_t code, uint8_t *read_data, uint16_t len, uint8_t *real_val)
+{
+    switch (code)
+    {
+    case DIC_0:
+    case DIC_100:
+    case DIC_200: 
+    case DIC_300:
+    case DIC_400:
+    case DIC_10000:
+    case DIC_10100:
+		case DIC_10001:
+		case DIC_10002:
+    case DIC_10200:
+    case DIC_10300:
+    case DIC_10400:
+    case DIC_20000:
+    case DIC_20100:
+    case DIC_20200:
+    case DIC_20300:
+    case DIC_20400:
+    case DIC_30000:
+    case DIC_40000:
+    case DIC_50000:
+    case DIC_60000:
+    case DIC_70000:
+    case DIC_80000:
+    case DIC_90000:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 4, "XXXXXX.XX", real_val);
+        break;
+    }
+    // 包含日期信息其原长度为8但其包含五个字节的日期时间长度所以read_data前三个字节为为数据信息,后五个字节为日期时间
+    case DIC_1010000:
+    case DIC_1020000:
+    case DIC_1010001:
+    case DIC_1020001:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 3, "XX.XXXX", real_val);
+        // 将剩余的 5 个字节拼接到 real_val 后面
+        for (int i = 0; i < 5; i++)
+        {
+            real_val[4 + i] = read_data[3 + i]-0x33;
+        }
+        break;
+    }
+		case DIC_201FF00:
+    case DIC_2010100:
+    case DIC_2010200:
+    case DIC_2010300:
+    case DIC_20C0100:
+    case DIC_20C0200:
+    case DIC_20C0300:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 2, "XXX.X", real_val);
+        break;
+    }
+    case DIC_2020100:
+    case DIC_2020200:
+    case DIC_2020300:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 3, "XXX.XXX", real_val);
+        break;
+    }
+    case DIC_2030000:
+    case DIC_2030100:
+    case DIC_2030200:
+    case DIC_2030300:
+    case DIC_2040000:
+    case DIC_2040100:
+    case DIC_2040200:
+    case DIC_2040300:
+    case DIC_2050000:
+    case DIC_2050100:
+    case DIC_2050200:
+    case DIC_2050300:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 3, "XX.XXXX", real_val);
+        break;
+    }
+    case DIC_2060000:
+    case DIC_2060100:
+    case DIC_2060200:
+    case DIC_2060300:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 2, "X.XXX", real_val);
+        break;
+    }
+    case DIC_2800002:
+    {
+        dlt645_data_parse_by_format_to_float(read_data, 2, "XX.XX", real_val);
+        break;
+    }
+		case DIC_5060101:
+		//case DIC_5040001:
+		{
+			for (uint16_t i = 0; i < len; i++)
+        {
+            real_val[i] = ((read_data[i] - 0x33) & 0x0f) + ((read_data[i] - 0x33) >> 4) * 10;
+        }
+			break;
+		}
+    case DIC_4000403:
+    case DIC_7000001:
+    case DIC_7000002:
+        for (uint16_t i = 0; i < len; i++)
+        {
+            real_val[i] = read_data[i] - 0x33;
+        }
+        break;
+    default:
+        for (uint16_t i = 0; i < len; i++)
+        {
+            real_val[i] = ((read_data[i] - 0x33) & 0x0f) + ((read_data[i] - 0x33) >> 4) * 10;
+        }
+        break;
+    }
+    return len;
+}
+
+/**
+ * Name:    dlt645_2007_read_data
+ * Brief:   DLT645-2007 数据读取
+ * Input:
+ *  @ctx:           645句柄
+ *  @addr:          从站地址
+ *  @code:          数据标识
+ *  @read_data:     数据存储地址
+ * Output:  None
+ */
+int dlt645_2007_read_data(dlt645_t *ctx,
+                          uint32_t code,
+                          uint8_t *read_data)
+{
+    uint8_t send_buf[DL645_2007_RD_CMD_LEN];
+    uint8_t read_buf[DL645_RESP_LEN];
+
+    memset(read_buf, 0, sizeof(read_buf));
+    memset(send_buf, 0, sizeof(send_buf));
+
+    memcpy(send_buf + 1, ctx->addr, DL645_ADDR_LEN);
+
+    send_buf[DL645_CONTROL_POS] = C_2007_CODE_RD;
+    send_buf[DL645_LEN_POS] = 4;
+
+    uint8_t send_code[4] = {0};
+    send_code[0] = (code & 0xff) + 0x33;
+    send_code[1] = ((code >> 8) & 0xff) + 0x33;
+    send_code[2] = ((code >> 16) & 0xff) + 0x33;
+    send_code[3] = ((code >> 24) & 0xff) + 0x33;
+
+    memcpy(send_buf + DL645_DATA_POS, send_code, 4);
+    if (dlt645_send_msg(ctx, send_buf, DL645_2007_RD_CMD_LEN) < 0)
+    {
+        DLT645_LOG("send data error!\n");
+        return -1;
+    }
+
+    if (dlt645_receive_msg(ctx, read_buf, DL645_RESP_LEN, code, DLT645_2007) < 0)
+    {
+        DLT645_LOG("receive msg error!\n");
+        return -1;
+    }
+
+    return dlt645_2007_parsing_data(code, read_buf + DL645_DATA_POS + 4, read_buf[DL645_LEN_POS] - 4, read_data);
+    // #define DL645_DATA_POS 10   //数据位置
+}
+
+/**
+ * Name:    dlt645_write_data
+ * Brief:   DLT645-2007 数据写入
+ * Input:
+ *  @ctx:           645句柄
+ *  @addr:          从站地址
+ *  @code:          数据标识
+ *  @write_data:    写入数据的指针
+ *  @write_len:     写入长度
+ * Output:  None
+ */
+int dlt645_write_data(dlt645_t *ctx,
+                      uint32_t addr,
+                      uint32_t code,
+                      uint8_t *write_data,
+                      uint8_t write_len)
+{
+    uint8_t send_buf[DL645_WR_LEN];
+    uint8_t read_buf[DL645_RESP_LEN];
+
+    memset(read_buf, 0, sizeof(read_buf));
+    memset(send_buf, 0, sizeof(send_buf));
+
+    memcpy(send_buf + 1, ctx->addr, DL645_ADDR_LEN);
+
+    send_buf[DL645_CONTROL_POS] = C_2007_CODE_WR;
+    send_buf[DL645_LEN_POS] = 12 + write_len;
+
+    uint8_t send_code[4] = {0};
+    send_code[0] = (code & 0xff) + 0x33;
+    send_code[1] = ((code >> 8) & 0xff) + 0x33;
+    send_code[2] = ((code >> 16) & 0xff) + 0x33;
+    send_code[3] = ((code >> 24) & 0xff) + 0x33;
+
+    for (uint8_t i = 0; i < write_len; i++)
+    {
+        write_data[i] += 0x33;
+    }
+
+    memcpy(send_buf + DL645_DATA_POS, send_code, 4);
+    memcpy(send_buf + DL645_DATA_POS + 12, write_data, write_len);
+    if (dlt645_send_msg(ctx, send_buf, 24 + write_len) < 0)
+    {
+        DLT645_LOG("send data error!\n");
+        return -1;
+    }
+
+    if (dlt645_receive_msg(ctx, read_buf, DL645_RESP_LEN, code, DLT645_2007) < 0)
+    {
+        DLT645_LOG("receive msg error!\n");
+        return -1;
+    }
+    return 0;
+}

+ 289 - 0
app/dlt/src/dlt645_data.c

@@ -0,0 +1,289 @@
+/*************************************************
+ Copyright (c) 2019
+ All rights reserved.
+ File name:     dlt645_data.c
+ Description:   DLT645 数据处理源文件
+ History:
+ 1. Version:    
+    Date:       2019-09-20
+    Author:     wangjunjie
+    Modify:     
+*************************************************/
+#include "dlt645_private.h"
+#include <string.h>
+#include <math.h>
+
+//字节位置枚举类型
+typedef enum
+{
+    BYTE_RESET = 0,   //重置
+    BYTE_LOW_ADDRESS, //低位
+    BYTE_HIGH_ADDRESS //高位
+} byte_part;
+
+/**
+ * Name:    _crc
+ * Brief:   crc和校验
+ * Input:
+ *  @msg:   校验数据包
+ *  @len:   数据包长度
+ * Output:  校验值
+ */
+int _crc(uint8_t *msg, int len)
+{
+    uint8_t crc = 0;
+    while (len--)
+    {
+        crc += *msg++;
+    }
+    return crc;
+}
+
+/**
+ * Name:    dlt645_common_check
+ * Brief:   645协议接收数据公共部分校验
+ * Input:
+ *  @msg:   校验数据包
+ *  @len:   数据包长度
+ *  @addr:  从站地址
+ * Output:  校验成功:0,校验失败:-1
+ */
+int dlt645_common_check(uint8_t *msg, int len, uint8_t *addr)
+{
+    //数据包长度校验
+    if (len < 7)
+    {
+        return -1;
+    }
+    //数据帧标志校验
+    if (msg[0] != DL645_START_CODE ||
+        msg[DL645_ADDR_LEN + 1] != DL645_START_CODE ||
+        msg[len - 1] != DL645_STOP_CODE)
+    {
+        DLT645_LOG("check code error!\n");
+        return -1;
+    }
+    //CRC校验
+    uint8_t crc = _crc(msg, len - 2);
+    if (crc != msg[len - 2])
+    {
+        DLT645_LOG("check crc error!\n");
+        return -1;
+    }
+    //控制码主从校验
+    if ((msg[DL645_CONTROL_POS] & C_TD_MASK) == (C_TD_MASTER << C_TD_POS))
+    {
+        DLT645_LOG("check control direction error!\n");
+        return -1;
+    }
+    //控制码应答校验
+    if ((msg[DL645_CONTROL_POS] & C_ACK_MASK) == (C_ACK_ERR << C_ACK_POS))
+    {
+        DLT645_LOG("check ACK error!\n");
+        return msg[len - 3];
+    }
+    //从站地址校验
+    if (memcmp(msg + 1, addr, 6) != 0)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+/**
+ * Name:    dec2bcd
+* Brief:   十进制转BCD码(目前支持32位数字大小)
+ * Input:
+ *  @val:   十进制值
+ * Output:  BCD码值
+ */
+uint32_t dec_to_bcd(uint32_t val)
+{
+    uint32_t data = 0;
+
+    if (val < 100)
+    {
+        uint8_t byte0 = val % 10;
+        uint8_t byte1 = val / 10;
+        data = (byte1 << 4) + byte0;
+    }
+    else if (val < 10000)
+    {
+        uint8_t byte0 = val % 10;
+        uint8_t byte1 = (val / 10) % 10;
+        uint8_t byte2 = (val / 100) % 10;
+        uint8_t byte3 = (val / 1000) % 10;
+        data = (byte3 << 12) +
+               (byte2 << 8) +
+               (byte1 << 4) + byte0;
+    }
+    else if (val < 1000000)
+    {
+        uint8_t byte0 = val % 10;
+        uint8_t byte1 = (val / 10) % 10;
+        uint8_t byte2 = (val / 100) % 10;
+        uint8_t byte3 = (val / 1000) % 10;
+        uint8_t byte4 = (val / 10000) % 10;
+        uint8_t byte5 = (val / 100000) % 10;
+        data = (byte5 << 20) +
+               (byte4 << 16) +
+               (byte3 << 12) +
+               (byte2 << 8) +
+               (byte1 << 4) + byte0;
+    }
+    else if (val < 100000000)
+    {
+        uint8_t byte0 = val % 10;
+        uint8_t byte1 = (val / 10) % 10;
+        uint8_t byte2 = (val / 100) % 10;
+        uint8_t byte3 = (val / 1000) % 10;
+        uint8_t byte4 = (val / 10000) % 10;
+        uint8_t byte5 = (val / 100000) % 10;
+        uint8_t byte6 = (val / 1000000) % 10;
+        uint8_t byte7 = (val / 10000000) % 10;
+        data = (byte7 << 28) +
+               (byte6 << 24) +
+               (byte5 << 20) +
+               (byte4 << 16) +
+               (byte3 << 12) +
+               (byte2 << 8) +
+               (byte1 << 4) + byte0;
+    }
+    return data;
+}
+
+/**
+ * Name:    str_to_bcd
+ * Brief:   字符串转BCD形式
+ * Input:
+ *  @str:               要转换的字符串
+ *  @bcd_store_address: 转换后的存储地址
+ *  @bcd_len:           BCD码总长度
+ * Output:  成功0,失败-1
+ */
+int str_to_bcd(char *str, uint8_t *bcd_store_address, uint16_t bcd_len)
+{
+    //字符串偏移
+    int str_pos = bcd_len * 2 - strlen(str);
+    //字符串比BCD码长度长
+    if (str_pos < 0)
+    {
+        return -1;
+    }
+    memset(bcd_store_address, 0, bcd_len);
+
+    for (int i = 0; i < strlen(str); i++)
+    {
+        if (str[i] >= '0' && str[i] <= '9')
+        {
+            bcd_store_address[(i + str_pos) / 2] |= (str[i] - '0') << (4 * ((i + 1 + (strlen(str) % 2)) % 2));
+        }
+        else
+        {
+            //当前字符不为数字,返回错误
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/**
+ * Name:    data_package_translate_to_int
+ * Brief:   将接收到的dlt645数据包中的数据转化为整数
+ * Input:
+ *  @read_data: 数据首地址
+ *  @len:       数据长度
+ * Output:  转化后的整数
+ */
+int data_package_translate_to_int(uint8_t *read_data, uint16_t len)
+{
+    //权值
+    uint8_t number_weight = 0;
+    //当前数组下标索引
+    uint8_t current_index = 0;
+    //当前解析字节位
+    uint8_t current_byte_part = BYTE_RESET;
+    //当前整数值
+    int i_value = 0;
+
+    while (len--)
+    {
+        current_byte_part = BYTE_LOW_ADDRESS;
+        do
+        {
+            switch (current_byte_part)
+            {
+            //当前处理字节低位
+            case BYTE_LOW_ADDRESS:
+                i_value += ((read_data[current_index] - 0x33) & 0x0f) * pow(10, number_weight);
+                number_weight++;
+                current_byte_part = BYTE_HIGH_ADDRESS;
+                break;
+            //当前处理字节高位
+            case BYTE_HIGH_ADDRESS:
+                i_value += ((read_data[current_index] - 0x33) >> 4) * pow(10, number_weight);
+                number_weight++;
+                current_byte_part = BYTE_RESET;
+                break;
+            }
+        } while (current_byte_part != BYTE_RESET);
+        current_index++;
+    }
+    return i_value;
+}
+
+/**
+ * Name:    dlt645_data_parse_by_format_to_float
+ * Brief:   根据数据格式将645协议读取的数据转换为真实数据并存储
+ *          !真实数据为浮点数据,需要注意的是无论读取数据长度是多少,存储数据长度都应是4字节
+ * Input:
+ *  @read_data:     645协议读取的数据
+ *  @read_len:      读取数据的长度
+ *  @data_format:   转换的数据格式,如 XX.XX,XX.XXX
+ * Output:  转换成功返回0,失败返回-1
+ */
+int dlt645_data_parse_by_format_to_float(uint8_t *read_data, uint16_t read_len, const char *data_format, uint8_t *store_address)
+{
+    //权值
+    int num_weight = 0;
+    int ival = data_package_translate_to_int(read_data, read_len);
+
+    for (int i = 0; i < strlen(data_format); i++)
+    {
+        if (*(data_format + i) == '.')
+        {
+            num_weight = strlen(data_format) - i - 1;
+            if (num_weight < 0)
+            {
+                return -1;
+            }
+            break;
+        }
+    }
+    float fval = ival / pow(10, num_weight);
+    memcpy(store_address, &fval, 4);
+    return 0;
+}
+
+int dlt645_data_parse_by_format_to_float_and_DATE(uint8_t *read_data, uint16_t read_len, const char *data_format, uint8_t *store_address)
+{
+    int num_weight = 0;
+    int ival = data_package_translate_to_int(read_data, read_len);
+
+    for (int i = 0; i < strlen(data_format); i++)
+    {
+        if (*(data_format + i) == '.')
+        {
+            num_weight = strlen(data_format) - i - 1;
+            if (num_weight < 0)
+            {
+                return -1;
+            }
+            break;
+        }
+    }
+    float fval = ival / pow(10, num_weight);
+    memcpy(store_address, &fval, 4);
+    return 0;
+}

+ 648 - 0
app/modbus/mmodbus.c

@@ -0,0 +1,648 @@
+
+#include "mmodbus.h"
+#include "usart.h"
+#include "delay.h"
+#include "log.h"
+MModBus_t mmodbus;
+
+// #####################################################################################################
+#if (_MMODBUS_RTU == 1)
+static const uint16_t wCRCTable[] =
+    {
+        0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
+        0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
+        0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
+        0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
+        0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
+        0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
+        0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
+        0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
+        0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
+        0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
+        0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
+        0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
+        0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
+        0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
+        0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
+        0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
+        0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
+        0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
+        0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
+        0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
+        0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
+        0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
+        0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
+        0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
+        0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
+        0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
+        0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
+        0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
+        0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
+        0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
+        0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
+        0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040};
+// crc校验
+uint16_t mmodbus_crc16(const uint8_t *nData, uint16_t wLength)
+{
+  uint8_t nTemp;
+  uint16_t wCRCWord = 0xFFFF;
+  while (wLength--)
+  {
+    nTemp = *nData++ ^ wCRCWord;
+    wCRCWord >>= 8;
+    wCRCWord ^= wCRCTable[nTemp];
+  }
+  return wCRCWord;
+}
+
+
+
+#endif
+volatile uint8_t flag;
+// #####################################################################################################
+//void mmodbus_callback(void)
+//{ 
+//	uint16_t data;
+//  if (RESET != usart_flag_get(_MMODBUS_USART, USART_FLAG_RBNE))
+//  {
+//		flag=0;
+//    if (mmodbus.rxIndex < _MMODBUS_RXSIZE - 1)
+//    {
+//      mmodbus.rxBuf[mmodbus.rxIndex] = usart_data_receive(_MMODBUS_USART);
+//      mmodbus.rxIndex++;
+//    }
+//    else
+//      usart_data_receive(_MMODBUS_USART);
+//  }
+
+//	if ((mmodbus.rxIndex > 0) && RESET != usart_flag_get(_MMODBUS_USART, USART_FLAG_IDLE) )
+//	{	
+//		mmodbus.done = 1;
+//		usart_data_receive(_MMODBUS_USART);
+//		usart_interrupt_flag_clear(_MMODBUS_USART, USART_INT_FLAG_IDLE);
+
+//		return;
+//	}
+//		else
+//		{
+//			data = usart_data_receive(_MMODBUS_USART);
+//			usart_interrupt_flag_clear(_MMODBUS_USART, USART_INT_FLAG_RBNE);
+//			
+//		}
+//  mmodbus.rxTime = gettick();
+//}
+
+void mmodbus_callback(void)
+{ 
+  if (RESET != usart_interrupt_flag_get(_MMODBUS_USART, USART_INT_FLAG_RBNE))
+  {
+    if (mmodbus.rxIndex < _MMODBUS_RXSIZE - 1)
+    {
+      mmodbus.rxBuf[mmodbus.rxIndex] = usart_data_receive(_MMODBUS_USART);
+      mmodbus.rxIndex++;
+    }
+    else
+		{
+      usart_data_receive(_MMODBUS_USART);
+		}
+		usart_interrupt_flag_clear(_MMODBUS_USART, USART_INT_FLAG_RBNE);
+  }
+	
+
+	if ((mmodbus.rxIndex > 0) && RESET != usart_interrupt_flag_get(_MMODBUS_USART, USART_INT_FLAG_IDLE))
+	{	
+		mmodbus.done = 1;
+		usart_data_receive(_MMODBUS_USART);
+		usart_interrupt_flag_clear(_MMODBUS_USART, USART_INT_FLAG_IDLE);
+
+		return;
+	}
+		else
+		{
+			usart_data_receive(USART0);
+			usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
+		}
+  mmodbus.rxTime = gettick();
+}
+
+
+// ##################################################################################################
+uint16_t mmodbus_receiveRaw(uint32_t timeout)
+{
+  uint32_t startTime = gettick();
+  while (1)
+  {
+    if (gettick() - startTime> timeout)
+      return 0;
+    if (mmodbus.done == 1)
+    {
+      return mmodbus.rxIndex;
+    }
+    mmodbus_delay(1);
+  }
+}
+// ##################################################################################################
+bool mmodbus_sendRaw(uint8_t *data, uint16_t size, uint32_t timeout)
+	{
+	while(mmodbus.txBusy == 1)
+	mmodbus_delay(1);
+	mmodbus.txBusy = 1;
+	memset(mmodbus.rxBuf, 0, _MMODBUS_RXSIZE);
+	mmodbus.rxIndex = 0;
+	mmodbus.done = 0;
+	uint32_t startTime = gettick();
+	portENTER_CRITICAL();
+	gpio_bit_write(_MMODBUS_CTRL_GPIO, _MMODBUS_CTRL_PIN,1);
+	mmodbus_delay(1);	
+	for (uint16_t i = 0; i < size; i++)
+	{
+		usart_data_transmit(_MMODBUS_USART,data[i]);
+		while (usart_flag_get(_MMODBUS_USART, USART_FLAG_TBE ) == RESET);		
+	} 
+	while (RESET == usart_flag_get(_MMODBUS_USART, USART_FLAG_TC));
+	gpio_bit_write(_MMODBUS_CTRL_GPIO, _MMODBUS_CTRL_PIN,0);
+	portEXIT_CRITICAL();
+	mmodbus.done=0;
+	mmodbus.txBusy = 0;
+
+	return true;
+}
+
+
+// ##################################################################################################
+bool mmodbus_init(uint32_t timeout)
+{
+  // HAL_GPIO_WritePin(_MMODBUS_CTRL_GPIO, _MMODBUS_CTRL_PIN, GPIO_PIN_RESET); 此处初始化在485 init过
+	gpio_bit_write(_MMODBUS_CTRL_GPIO, _MMODBUS_CTRL_PIN,0);
+  memset(&mmodbus, 0, sizeof(mmodbus));
+  mmodbus.timeout = timeout;
+  return true;
+}
+// ##################################################################################################
+void mmodbus_set16bitOrder(MModBus_16bitOrder_t MModBus_16bitOrder_)
+{
+  mmodbus.byteOrder16 = MModBus_16bitOrder_;
+}
+// ##################################################################################################
+void mmodbus_set32bitOrder(MModBus_32bitOrder_t MModBus_32bitOrder_)
+{
+  mmodbus.byteOrder32 = MModBus_32bitOrder_;
+}
+// ##################################################################################################
+bool mmodbus_readCoil(uint8_t slaveAddress, uint16_t number, uint8_t *data)
+{
+  return mmodbus_readCoils(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+// 读线圈
+bool mmodbus_readCoils(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_ReadCoilStatus;
+  txData[2] = (startnumber & 0xFF00) >> 8;
+  txData[3] = (startnumber & 0x00FF);
+  txData[4] = (length & 0xFF00) >> 8;
+  txData[5] = (length & 0x00FF);
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+  if (recLen == 0)
+    return false;
+  if (mmodbus.rxBuf[0] != slaveAddress)
+    return false;
+  if (mmodbus.rxBuf[1] != MModbusCMD_ReadCoilStatus)
+    return false;
+  crc = mmodbus_crc16(mmodbus.rxBuf, mmodbus.rxBuf[2] + 3);
+  if (((crc & 0x00FF) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 3]) || (((crc & 0xFF00) >> 8) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 4]))
+    return false;
+  if (data != NULL)
+    memcpy(data, &mmodbus.rxBuf[3], mmodbus.rxBuf[2]);
+  return true;
+#endif
+#if (_MMODBUS_ASCII == 1)
+
+#endif
+}
+// ##################################################################################################
+bool mmodbus_readDiscreteInput(uint8_t slaveAddress, uint16_t number, uint8_t *data)
+{
+  return mmodbus_readDiscreteInputs(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+// 读取线圈功能码处理
+bool mmodbus_readDiscreteInputs(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_ReadDiscreteInputs;
+  txData[2] = (startnumber & 0xFF00) >> 8;
+  txData[3] = (startnumber & 0x00FF);
+  txData[4] = (length & 0xFF00) >> 8;
+  txData[5] = (length & 0x00FF);
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+  if (recLen == 0)
+    return false;
+  if (mmodbus.rxBuf[0] != slaveAddress)
+    return false;
+  if (mmodbus.rxBuf[1] != MModbusCMD_ReadDiscreteInputs)
+    return false;
+  crc = mmodbus_crc16(mmodbus.rxBuf, mmodbus.rxBuf[2] + 3);
+  if (((crc & 0x00FF) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 3]) || (((crc & 0xFF00) >> 8) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 4]))
+    return false;
+  if (data != NULL)
+    memcpy(data, &mmodbus.rxBuf[3], mmodbus.rxBuf[2]);
+  return true;
+#endif
+}
+// ##################################################################################################
+
+bool mmodbus_readInputRegisters8i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_ReadInputRegisters;
+  txData[2] = (startnumber & 0xFF00) >> 8;
+  txData[3] = (startnumber & 0x00FF);
+  txData[4] = (length & 0xFF00) >> 8;
+  txData[5] = (length & 0x00FF);
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+  if (recLen == 0)
+    return false;
+  if (mmodbus.rxBuf[0] != slaveAddress)
+    return false;
+  if (mmodbus.rxBuf[1] != MModbusCMD_ReadInputRegisters)
+    return false;
+  crc = mmodbus_crc16(mmodbus.rxBuf, mmodbus.rxBuf[2] + 3);
+  if (((crc & 0x00FF) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 3]) || (((crc & 0xFF00) >> 8) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 4]))
+    return false;
+  if (data != NULL)
+    memcpy(data, &mmodbus.rxBuf[3], mmodbus.rxBuf[2]);
+  return true;
+#endif
+}
+// ##################################################################################################
+bool mmodbus_readInputRegister32f(uint8_t slaveAddress, uint16_t number, float *data)
+{
+  return mmodbus_readInputRegisters32f(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readInputRegisters32f(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, float *data)
+{
+  bool ret = mmodbus_readInputRegisters8i(slaveAddress, startnumber, length * 2, (uint8_t *)data);
+  if (ret == true)
+  {
+    for (uint16_t i = 0; i < length; i++)
+    {
+      uint8_t tmp1[4], tmp2[4];
+      switch (mmodbus.byteOrder32)
+      {
+      case MModBus_32bitOrder_DCBA:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[3];
+        tmp2[1] = tmp1[2];
+        tmp2[2] = tmp1[1];
+        tmp2[3] = tmp1[0];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      case MModBus_32bitOrder_BADC:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[1];
+        tmp2[1] = tmp1[0];
+        tmp2[2] = tmp1[3];
+        tmp2[3] = tmp1[2];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      case MModBus_32bitOrder_CDAB:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[2];
+        tmp2[1] = tmp1[3];
+        tmp2[2] = tmp1[0];
+        tmp2[3] = tmp1[1];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      default:
+
+        break;
+      }
+    }
+    return true;
+  }
+  else
+    return false;
+}
+// ##################################################################################################
+bool mmodbus_readInputRegister32i(uint8_t slaveAddress, uint16_t number, uint32_t *data)
+{
+  return mmodbus_readInputRegisters32i(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readInputRegisters32i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint32_t *data)
+{
+  return mmodbus_readInputRegisters32f(slaveAddress, startnumber, length, (float *)data);
+}
+// ##################################################################################################
+bool mmodbus_readInputRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t *data)
+{
+  return mmodbus_readInputRegisters16i(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readInputRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data)
+{
+  bool ret = mmodbus_readInputRegisters8i(slaveAddress, startnumber, length * 1, (uint8_t *)data);
+  if (ret == true)
+  {
+    uint8_t tmp1[2], tmp2[2];
+    for (uint16_t i = 0; i < length; i++)
+    {
+      switch (mmodbus.byteOrder16)
+      {
+      case MModBus_16bitOrder_AB:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[0];
+        tmp2[1] = tmp1[1];
+        memcpy(&data[i], tmp2, 2);
+        break;
+      default:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[1];
+        tmp2[1] = tmp1[0];
+        memcpy(&data[i], tmp2, 2);
+        break;
+      }
+    }
+    return true;
+  }
+  else
+    return false;
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegisters8i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_ReadHoldingRegisters;
+  txData[2] = (startnumber & 0xFF00) >> 8;
+  txData[3] = (startnumber & 0x00FF);
+  txData[4] = (length & 0xFF00) >> 8;
+  txData[5] = (length & 0x00FF);
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(100);
+  if (recLen == 0)
+    return false;
+  if (mmodbus.rxBuf[0] != slaveAddress)
+    return false;
+  if (mmodbus.rxBuf[1] != MModbusCMD_ReadHoldingRegisters)
+    return false;
+  crc = mmodbus_crc16(mmodbus.rxBuf, mmodbus.rxBuf[2] + 3);
+  if (((crc & 0x00FF) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 3]) || (((crc & 0xFF00) >> 8) != mmodbus.rxBuf[mmodbus.rxBuf[2] + 4]))
+    return false;
+  if (data != NULL)
+  {
+    for (uint8_t i = 0; i < mmodbus.rxBuf[2]; i += 2)
+    {
+      uint8_t H = mmodbus.rxBuf[i + 3];
+      mmodbus.rxBuf[i + 3] = mmodbus.rxBuf[i + 3 + 1];
+      mmodbus.rxBuf[i + 3 + 1] = H;
+    }
+    memcpy(data, &mmodbus.rxBuf[3], mmodbus.rxBuf[2]);
+  }
+  return true;
+#endif
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegister32f(uint8_t slaveAddress, uint16_t number, float *data)
+{
+  return mmodbus_readHoldingRegisters32f(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegisters32f(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, float *data)
+{
+  bool ret = mmodbus_readHoldingRegisters8i(slaveAddress, startnumber, length * 2, (uint8_t *)data);
+  if (ret == true)
+  {
+    for (uint16_t i = 0; i < length; i++)
+    {
+      uint8_t tmp1[4], tmp2[4];
+      switch (mmodbus.byteOrder32)
+      {
+      case MModBus_32bitOrder_DCBA:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[3];
+        tmp2[1] = tmp1[2];
+        tmp2[2] = tmp1[1];
+        tmp2[3] = tmp1[0];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      case MModBus_32bitOrder_BADC:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[1];
+        tmp2[1] = tmp1[0];
+        tmp2[2] = tmp1[3];
+        tmp2[3] = tmp1[2];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      case MModBus_32bitOrder_CDAB:
+        memcpy(tmp1, &data[i], 4);
+        tmp2[0] = tmp1[2];
+        tmp2[1] = tmp1[3];
+        tmp2[2] = tmp1[0];
+        tmp2[3] = tmp1[1];
+        memcpy(&data[i], tmp2, 4);
+        break;
+      default:
+
+        break;
+      }
+    }
+    return true;
+  }
+  else
+    return false;
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegister32i(uint8_t slaveAddress, uint16_t number, uint32_t *data)
+{
+  return mmodbus_readHoldingRegisters32i(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegisters32i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint32_t *data)
+{
+  return mmodbus_readHoldingRegisters32f(slaveAddress, startnumber, length, (float *)data);
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t *data)
+{
+  return mmodbus_readHoldingRegisters16i(slaveAddress, number, 1, data);
+}
+// ##################################################################################################
+bool mmodbus_readHoldingRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data)
+{
+  bool ret = mmodbus_readHoldingRegisters8i(slaveAddress, startnumber, length * 1, (uint8_t *)data);
+  if (ret == true)
+  {
+    uint8_t tmp1[2], tmp2[2];
+    for (uint16_t i = 0; i < length; i++)
+    {
+      switch (mmodbus.byteOrder16)
+      {
+      case MModBus_16bitOrder_AB:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[0];
+        tmp2[1] = tmp1[1];
+        memcpy(&data[i], tmp2, 2);
+        break;
+      default:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[1];
+        tmp2[1] = tmp1[0];
+        memcpy(&data[i], tmp2, 2);
+        break;
+      }
+    }
+    return true;
+  }
+  else
+    return false;
+}
+// ##################################################################################################
+bool mmodbus_writeCoil(uint8_t slaveAddress, uint16_t number, uint8_t data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_WriteSingleCoil;
+  txData[2] = (number & 0xFF00) >> 8;
+  txData[3] = (number & 0x00FF);
+  if (data == 0)
+    txData[4] = 0;
+  else
+    txData[4] = 0xFF;
+  txData[5] = 0;
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+  if (recLen == 0)
+    return false;
+  if (memcmp(txData, mmodbus.rxBuf, 8) == 0)
+    return true;
+  else
+    return false;
+#endif
+#if (_MMODBUS_ASCII == 1)
+
+#endif
+}
+
+// ##################################################################################################
+bool mmodbus_writeHoldingRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t data)
+{
+#if (_MMODBUS_RTU == 1)
+  uint8_t txData[8];
+  txData[0] = slaveAddress;
+  txData[1] = MModbusCMD_WriteSingleRegister;
+  txData[2] = (number & 0xFF00) >> 8;
+  txData[3] = (number & 0x00FF);
+  txData[4] = (data & 0xFF00) >> 8;
+  txData[5] = data & 0x00FF;
+  static uint16_t crc;
+  crc = mmodbus_crc16(txData, 6);
+  txData[6] = (crc & 0x00FF);
+  txData[7] = (crc & 0xFF00) >> 8;
+  mmodbus_sendRaw(txData, 8, 100);
+  uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+  if (recLen == 0)
+    return false;
+  if (memcmp(txData, mmodbus.rxBuf, 8) == 0)
+    return true;
+  else
+    return false;
+#endif
+#if (_MMODBUS_ASCII == 1)
+
+#endif
+}
+// ##################################################################################################
+bool mmodbus_writeHoldingRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data)
+{
+#if (_MMODBUS_RTU == 1)
+  if (length == 1)
+  {
+    return mmodbus_writeHoldingRegister16i(slaveAddress, startnumber, data[0]);
+  }
+  else
+  {
+    uint8_t txData[7 + length * 2 + 2];
+    txData[0] = slaveAddress;
+    txData[1] = MModbusCMD_WriteMultipleRegisters;
+    txData[2] = (startnumber & 0xFF00) >> 8;
+    txData[3] = (startnumber & 0x00FF);
+    txData[4] = (length & 0xFF00) >> 8;
+    txData[5] = (length & 0x00FF);
+    txData[6] = (length * 2);
+    uint8_t tmp1[2], tmp2[2];
+    for (uint16_t i = 0; i < length; i++)
+    {
+      switch (mmodbus.byteOrder16)
+      {
+      case MModBus_16bitOrder_AB:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[1];
+        tmp2[1] = tmp1[0];
+        memcpy(&txData[7 + i * 2], tmp2, 2);
+        break;
+      default:
+        memcpy(tmp1, &data[i], 2);
+        tmp2[0] = tmp1[0];
+        tmp2[1] = tmp1[1];
+        memcpy(&txData[7 + i * 2], tmp2, 2);
+        break;
+      }
+    }
+    static uint16_t crc;
+    crc = mmodbus_crc16(txData, 7 + length * 2);
+    txData[7 + length * 2 + 0] = (crc & 0x00FF);
+    txData[7 + length * 2 + 1] = (crc & 0xFF00) >> 8;
+    mmodbus_sendRaw(txData, 7 + length * 2 + 2, 100);
+    uint16_t recLen = mmodbus_receiveRaw(mmodbus.timeout);
+    if (recLen == 0)
+      return false;
+    crc = mmodbus_crc16(txData, 6);
+    txData[6] = (crc & 0x00FF);
+    txData[7] = (crc & 0xFF00) >> 8;
+    if (memcmp(txData, mmodbus.rxBuf, 8) == 0)
+      return true;
+    else
+      return false;
+  }
+#endif
+#if (_MMODBUS_ASCII == 1)
+
+#endif
+}
+// ##################################################################################################
+

+ 164 - 0
app/modbus/mmodbus.h

@@ -0,0 +1,164 @@
+#ifndef _M_MODBUS_H_
+#define _M_MODBUS_H_
+
+
+/*
+  Author:     Nima Askari
+  WebSite:    http://www.github.com/NimaLTD
+  Instagram:  http://instagram.com/github.NimaLTD
+  Youtube:    https://www.youtube.com/channel/UCUhY7qY1klJm1d2kulr9ckw
+  
+  Version:    1.3.2
+  
+  Reversion History:
+  
+  (1.3.2)
+  Speedup receiver, add write multiple holding
+    
+  (1.3.1)
+  Remove delay in sending function when DMA is disabled
+  
+  (1.3.0)
+  Add 16 bit order
+  
+  (1.2.1)
+  bug fixed.
+  
+  (1.2.0)
+  add read 32bit register order.
+  
+  (1.1.2)
+  fix read holding register.
+  
+  (1.1.1)
+  fix functions name.
+  
+  (1.1.0)
+  add 16bit,32bit,float read.
+  
+  (1.0.1)
+  add delay in receive routin.
+  
+  (1.0.0)
+  First release.
+*/ 
+
+#include "gd32f30x.h"
+#include  "mmodbusConfig.h"
+//#include  "usart.h"
+#include  <stdbool.h>
+#include  <string.h>
+#include  <stdio.h>
+#include  <stdint.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#define   mmodbus_delay(x) 	delay_ms(x)
+
+
+/*
+功能码
+MModbusCMD_ReadCoilStatus(读线圈状态):用于读取一个或多个逻辑线圈的状态。
+MModbusCMD_ReadDiscreteInputs(读离散输入状态):用于读取一个或多个数字输入信号的状态。
+MModbusCMD_ReadHoldingRegisters(读保持寄存器):用于读取一个或多个保持寄存器的值。
+MModbusCMD_ReadInputRegisters(读输入寄存器):用于读取一个或多个输入寄存器的值。
+MModbusCMD_WriteSingleCoil(写单个线圈):用于控制单个逻辑线圈的状态。
+MModbusCMD_WriteSingleRegister(写单个保持寄存器):用于写入单个保持寄存器的值。
+MModbusCMD_WriteMultipleCoils(写多个线圈):用于控制多个逻辑线圈的状态。
+MModbusCMD_WriteMultipleRegisters(写多个保持寄存器):用于写入多个保持寄存器的值。
+*/
+typedef enum
+{
+  MModbusCMD_ReadCoilStatus = 1,
+  MModbusCMD_ReadDiscreteInputs = 2,
+  MModbusCMD_ReadHoldingRegisters = 3,
+  MModbusCMD_ReadInputRegisters = 4,
+  MModbusCMD_WriteSingleCoil = 5,
+  MModbusCMD_WriteSingleRegister = 6,
+  MModbusCMD_WriteMultipleCoils = 15,
+  MModbusCMD_WriteMultipleRegisters = 16
+  
+}MModbusCMD_t;
+
+//大小端
+typedef enum
+{
+  MModBus_16bitOrder_AB=1,
+  MModBus_16bitOrder_BA=2,
+  
+}MModBus_16bitOrder_t;
+
+typedef enum
+{
+  MModBus_32bitOrder_ABCD = 0,
+  MModBus_32bitOrder_DCBA,
+  MModBus_32bitOrder_BADC,
+  MModBus_32bitOrder_CDAB,  
+  
+}MModBus_32bitOrder_t;
+
+/*
+	rxIndex:接收缓冲区的当前接收位置。
+	rxBuf:接收缓冲区。
+	rxTime:最近一次接收数据的时间戳。
+	txBusy:发送是否忙碌的标志位。
+	timeout:超时时间。
+	byteOrder16:16 位数据的字节序(即高位字节在前还是低位字节在前)。
+	byteOrder32:32 位数据的字节序。
+	done:数据是否接收完成的标志位。
+	txDmaDone:DMA 发送是否完成的标志位(该成员只在使用 DMA 发送时有效)。
+*/
+typedef struct
+{
+  uint16_t              rxIndex;  
+  uint8_t               rxBuf[_MMODBUS_RXSIZE];
+  uint32_t              rxTime;
+  uint8_t               txBusy;
+  uint32_t              timeout; 
+  MModBus_16bitOrder_t  byteOrder16;
+  MModBus_32bitOrder_t  byteOrder32;
+	uint8_t								done;
+  #if (_MMODBUS_TXDMA == 1)
+  uint8_t             txDmaDone;
+  #endif  
+  
+}MModBus_t;
+
+//##################################################################################################
+
+void    mmodbus_callback(void);
+bool    mmodbus_sendRaw(uint8_t *data, uint16_t size, uint32_t timeout);
+uint16_t mmodbus_crc16(const uint8_t *nData, uint16_t wLength); 
+void    mmodbus_callback_txDMA(void);
+
+bool    mmodbus_init(uint32_t setTimeout);
+void    mmodbus_set16bitOrder(MModBus_16bitOrder_t MModBus_16bitOrder_);
+void    mmodbus_set32bitOrder(MModBus_32bitOrder_t MModBus_32bitOrder_);
+//  coils numbers 00001 to 09999
+bool    mmodbus_readCoil(uint8_t slaveAddress, uint16_t number, uint8_t *data);
+bool    mmodbus_readCoils(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data);
+//  discrete input 10001 to 19999
+bool    mmodbus_readDiscreteInput(uint8_t slaveAddress, uint16_t number, uint8_t *data);
+bool    mmodbus_readDiscreteInputs(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint8_t *data);
+//  input register 30001 to 39999
+bool    mmodbus_readInputRegister32f(uint8_t slaveAddress, uint16_t number, float *data);
+bool    mmodbus_readInputRegisters32f(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, float *data);
+bool    mmodbus_readInputRegister32i(uint8_t slaveAddress, uint16_t number, uint32_t *data);
+bool    mmodbus_readInputRegisters32i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint32_t *data);
+bool    mmodbus_readInputRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t *data);
+bool    mmodbus_readInputRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data);
+//  holding register 40001 to 49999
+bool    mmodbus_readHoldingRegister32f(uint8_t slaveAddress, uint16_t number, float *data);
+bool    mmodbus_readHoldingRegisters32f(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, float *data);
+bool    mmodbus_readHoldingRegister32i(uint8_t slaveAddress, uint16_t number, uint32_t *data);
+bool    mmodbus_readHoldingRegisters32i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint32_t *data);
+bool    mmodbus_readHoldingRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t *data);
+bool    mmodbus_readHoldingRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data);
+// coils numbers 00001 to 09999
+bool    mmodbus_writeCoil(uint8_t slaveAddress, uint16_t number, uint8_t data);
+//  holding register 40001 to 49999
+bool    mmodbus_writeHoldingRegister16i(uint8_t slaveAddress, uint16_t number, uint16_t data);
+bool    mmodbus_writeHoldingRegisters16i(uint8_t slaveAddress, uint16_t startnumber, uint16_t length, uint16_t *data);
+uint16_t mmodbus_crc16(const uint8_t *nData, uint16_t wLength);
+
+//##################################################################################################
+#endif

+ 18 - 0
app/modbus/mmodbusConfig.h

@@ -0,0 +1,18 @@
+#ifndef _MMODBUS_CONFIG_H_
+#define _MMODBUS_CONFIG_H_
+
+#define _MMODBUS_FREERTOS         0
+#define _MMODBUS_RTU              1
+#define _MMODBUS_ASCII            0 //  not implemented yet
+#define _MMODBUS_USART            USART0            
+#define _MMODBUS_RXSIZE           64  
+#define _MMODBUS_TXDMA            0   
+
+#define _MMODBUS_CTRL_GPIO        DE485_GPIO_PORT
+#define _MMODBUS_CTRL_PIN         DE485_PIN
+#define gettick( )                           ( xTaskGetTickCount() )
+
+#if (_MMODBUS_RTU == 1) && (_MMODBUS_ASCII == 1)
+#error please select _MMODBUS_RTU or _MMODBUS_ASCII
+#endif
+#endif

+ 2 - 2
app/mqttclient/mqttclient/mqttclient.c

@@ -981,9 +981,9 @@ static int mqtt_connect_with_results(mqtt_client_t* c)
 #else
     rc = network_init(c->mqtt_network, c->mqtt_host, c->mqtt_port, NULL);
 #endif
-
     rc = network_connect(c->mqtt_network);
-    if (MQTT_SUCCESS_ERROR != rc) {
+		
+	  if (MQTT_SUCCESS_ERROR != rc) {
         if (NULL != c->mqtt_network) {
             network_release(c->mqtt_network);
             RETURN_ERROR(rc);

+ 1 - 1
app/mqttclient/mqttclient/mqttclient.h

@@ -95,7 +95,7 @@ typedef struct mqtt_client {
     char                        *mqtt_user_name;
     char                        *mqtt_password;
     char                        *mqtt_host;
-    char                        *mqtt_port;
+		char                        *mqtt_port;
     char                        *mqtt_ca;
     void                        *mqtt_reconnect_data;
     uint8_t                     *mqtt_read_buf;