燕十三 8 лет назад
Родитель
Сommit
696bc2e86a
9 измененных файлов с 2624 добавлено и 0 удалено
  1. 13 0
      SConscript
  2. 105 0
      example/gagent_cloud_demo.c
  3. 292 0
      gagent_cloud.c
  4. 67 0
      gagent_cloud.h
  5. 172 0
      gagent_def.h
  6. 577 0
      gagent_httpc.c
  7. 940 0
      gagent_lan.c
  8. 265 0
      gagent_mqtt.c
  9. 193 0
      gagent_tool.c

+ 13 - 0
SConscript

@@ -0,0 +1,13 @@
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+
+if GetDepend(['PKG_USING_GAGENT_CLOUD_EXAMPLE']):
+	src += Glob('example/*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('gagent_cloud', src, depend = ['PKG_USING_GAGENT_CLOUD', 'RT_USING_LWIP','PKG_USING_WEBCLIENT', 'PKG_USING_PAHOMQTT'], CPPPATH = CPPPATH)
+
+Return('group')

+ 105 - 0
example/gagent_cloud_demo.c

@@ -0,0 +1,105 @@
+/*
+ * File      : gagent_tool.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include <rtthread.h>
+
+#include "gagent_cloud.h"
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#endif
+
+#define     DEMO_PRODUCT_KEY                    "1371df627fa64e849f32fe17ebd5fd38"
+#define     DEMO_PRODUCT_KEY_SECRET             "067a83b650544d979bb3d4d147f32034"   
+#define     DEMO_MAC                            "\xBC\x12\x34\x56\x78\x23"
+
+static gagent_cloud_param gagent_param;
+
+int gagent_read_param(void *param, rt_uint32_t len)
+{
+    /* read param */
+    
+    return RT_EOK;
+}
+
+int gagent_write_param(void *param, rt_uint32_t len)
+{
+    /* write param */
+    
+    return RT_EOK;
+}
+
+int gagent_recv_packet(rt_uint8_t from, rt_uint8_t action, rt_uint8_t *kv, rt_uint16_t kv_len)
+{
+    /* please read product protocol */
+    uint8_t power;
+    
+    switch(action)
+    {
+        case ACTION_CONTROL: 
+            rt_kprintf("ACTION_CONTROL\r\n");
+            power = *(kv + 1);
+            rt_kprintf("power:%d\n", power);
+            gagent_cloud_send_packet(ACTION_REPORT_STATUS, &power, 1);
+        break;
+
+        case ACTION_READ_STATUS:
+            rt_kprintf("ACTION_READ_STATUS\r\n");
+//            gagent_cloud_send_packet(ACTION_READ_STATUS_ACK, buf, buf_len);
+        break;
+
+        case ACTION_TRANS_RECV:
+            rt_kprintf("this is your raw data from app\r\n");
+        break;
+        
+        case ACTION_PUSH_OTA:
+            rt_kprintf("ACTION_PUSH_OTA\r\n");
+        break;
+    }
+    
+    return RT_EOK;
+}
+
+int gagent_cloud(void)
+{
+    int rc = RT_EOK;
+
+    rt_memset(&gagent_param, 0, sizeof(gagent_param));
+    //
+    strcpy(gagent_param.product_key, DEMO_PRODUCT_KEY);
+    strcpy(gagent_param.product_secret, DEMO_PRODUCT_KEY_SECRET);
+    strcpy(gagent_param.mac, DEMO_MAC);
+    gagent_param.read_param_callback = gagent_read_param;
+    gagent_param.write_param_callback = gagent_write_param;
+    gagent_param.recv_packet_callback = gagent_recv_packet;
+    //
+    gagent_cloud_start(&gagent_param);
+    
+    return rc;
+}
+#ifdef RT_USING_FINSH
+MSH_CMD_EXPORT(gagent_cloud, gagent cloud demo);
+
+FINSH_FUNCTION_EXPORT(gagent_cloud, "gagent cloud test");
+#endif
+

+ 292 - 0
gagent_cloud.c

@@ -0,0 +1,292 @@
+/*
+ * File      : gagent_cloud.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include <rtthread.h>
+
+#include "gagent_def.h"
+#include "gagent_cloud.h"
+//
+
+#if !defined(PKG_PAHOMQTT_SUBSCRIBE_HANDLERS) || (PKG_PAHOMQTT_SUBSCRIBE_HANDLERS < 2)
+#error "must defined PKG_PAHOMQTT_SUBSCRIBE_HANDLERS >= 2 in menuconfig"
+#endif
+
+
+static con_st con;        //config info
+static gagent_cloud_param con_param = {0};
+//
+cloud_st *cloud = RT_NULL;     //cloud handle
+lan_st *lan = RT_NULL;       //lan handle
+
+
+
+int gagent_cloud_send_packet(rt_uint8_t action, rt_uint8_t *buf, rt_uint16_t buf_len)
+{
+    int rc = RT_EOK;
+
+    RT_ASSERT(action != 0);
+
+    rc = gagent_mqtt_send_packet(cloud, action, buf, buf_len);
+    if(rc != RT_EOK)
+    {
+        gagent_err("gagent_mqtt_send_packet failed:%d\n", rc);
+    }
+
+    rc = gagent_lan_send_packet(lan, action, buf, buf_len);
+    if(rc != RT_EOK)
+    {
+        gagent_err("gagent_lan_send_packet failed:%d\n", rc);
+    }
+    
+    return rc;
+}
+
+int gagent_cloud_recv_packet(rt_uint8_t from, rt_uint8_t action, rt_uint8_t *kv, rt_uint16_t kv_len)
+{
+    int rc = RT_EOK;
+    gagent_dbg("from:%s\n", (from == CMD_FROM_LAN) ? "lan packet" : "mqtt packet");
+    
+    if(con_param.recv_packet_callback != RT_NULL)
+        rc = con_param.recv_packet_callback(from, action, kv, kv_len);
+        
+    return rc;
+}
+
+static int gagent_cloud_parse_config(con_st *con)
+{
+    rt_bool_t write_flag = RT_FALSE;
+
+    RT_ASSERT(con != RT_NULL);
+
+    //read file
+    memset(con, 0, sizeof(con_st));
+            
+    if(con_param.read_param_callback(con, sizeof(con_st)) != RT_EOK)
+        gagent_err("read param failed!\n");
+    
+    if(con->mac[0] == 0 || memcmp(con->mac, con_param.mac, sizeof(con->mac)) != 0)
+    {
+        rt_memset(con->did, 0, sizeof(con->did));
+        //
+        rt_memset(con->mac, 0, sizeof(con->mac));
+        rt_memcpy(con->mac, con_param.mac, sizeof(con->mac) - 1);
+        write_flag = RT_TRUE;
+        gagent_dbg("con->mac changed!\n");
+    }
+
+    if(con->pk[0] == 0 || strcmp(con->pk, con_param.product_key) != 0)
+    {
+        rt_memset(con->did, 0, sizeof(con->did));
+        //
+        rt_memset(con->pk, 0, sizeof(con->pk));
+        rt_strncpy(con->pk, con_param.product_key, sizeof(con->pk) - 1);
+        write_flag = RT_TRUE;
+        gagent_dbg("con->pk changed!\n");
+    }
+    
+    if(con->pk_secret[0] == 0 || strcmp(con->pk_secret, con_param.product_secret) != 0)
+    {
+        rt_memset(con->did, 0, sizeof(con->did));
+        //
+        rt_memset(con->pk_secret, 0, sizeof(con->pk_secret));
+        rt_strncpy(con->pk_secret, con_param.product_secret, sizeof(con->pk_secret) - 1);
+        write_flag = RT_TRUE;
+        gagent_dbg("product secret changed!\n");
+    }
+    
+    if(con->hard_version[0] == 0 || strcmp(con->hard_version, HARD_VERSION) != 0)
+    {
+        rt_memset(con->hard_version, 0, sizeof(con->hard_version));
+        rt_strncpy(con->hard_version, HARD_VERSION, sizeof(con->hard_version) - 1);
+        write_flag = RT_TRUE;
+        gagent_dbg("hard_version changed!\n");
+    }
+    
+    if(con->soft_version[0] == 0 || strcmp(con->soft_version, SOFT_VERSION) != 0)
+    {
+        rt_memset(con->soft_version, 0, sizeof(con->soft_version));
+        rt_strncpy(con->soft_version, SOFT_VERSION, sizeof(con->soft_version) - 1);
+        write_flag = RT_TRUE;
+        gagent_dbg("soft_verson changed!\n");
+    }
+
+    if(con->passcode[0] == 0)
+    {
+        //passcode is empty
+        rt_memset(con->passcode, 0, sizeof(con->passcode));
+        rt_memcpy(con->passcode, con->pk, 10);
+        write_flag = RT_TRUE;
+        gagent_dbg("passcode empty!\n");
+    }
+
+#if (PKG_GAGENT_CLOUD_DEBUG == 1)
+	{
+		rt_uint8_t i;
+        rt_kprintf("mac: ");
+        for(i = 0; i < MAX_MAC_LEN; i ++)
+        {
+            rt_kprintf("%02x ", con->mac[i]);
+        }
+        rt_kprintf("\r\n");
+        rt_kprintf("did:%s\n", con->did);
+        rt_kprintf("passcode:%s\n", con->passcode);
+        rt_kprintf("pk:%s\n", con->pk);
+        rt_kprintf("pk_secret:%s\n", con->pk_secret);
+        rt_kprintf("hard_version:%s\n", con->hard_version);
+        rt_kprintf("soft_version:%s\n", con->soft_version);
+	}
+#endif
+	
+    if(write_flag)
+    {
+        gagent_dbg("write param!\n");
+         con_param.write_param_callback(con, sizeof(con_st));
+    }
+    
+    return RT_EOK;
+}
+
+static int gagent_cloud_init(cloud_st *cloud)
+{
+    int rc = RT_EOK;
+
+    if(cloud->con->did[0] == 0)
+    {
+        rt_memset(cloud->con->did, 0, sizeof(cloud->con->did));
+
+        rc = gagent_cloud_register(cloud);
+        if(rc != RT_EOK)
+        {
+            gagent_err("gagent_cloud_register failed! errno:%d\n", rc);
+            return rc;
+        }
+        //write param
+        con_param.write_param_callback(cloud->con, sizeof(con_st));
+    }
+
+    rc = gagent_cloud_provision(cloud);
+
+    return RT_EOK;
+
+}
+
+void gagent_cloud_thread(void *parameter)
+{
+    int rc = RT_EOK;
+
+    rc = gagent_cloud_parse_config(&con);
+    if(rc != RT_EOK)
+    {
+        gagent_err("gagent_cloud_parse_config failed!\n");
+        goto __exit;
+    }
+
+    rc = gagent_cloud_init(cloud);
+    if(cloud == RT_NULL)
+    {
+        gagent_err("gagent_cloud_init failed!\n");
+        goto __exit;
+    }
+
+    rc = gagent_lan_init(lan);
+    if(rc != RT_EOK)
+    {
+        gagent_err("gagent_cloud_lan_init failed!\n");
+        goto __exit;
+    }
+		
+    rc = gagent_mqtt_init(cloud);
+    if(rc != RT_EOK)
+    {
+        gagent_err("gagent_cloud_mqtt_init failed!\n");
+        goto __exit;
+    }
+
+    rc = gagent_cloud_check_ota(cloud);
+
+__exit:
+    return;
+}
+
+int gagent_cloud_start(gagent_cloud_param *param)
+{
+    int rc = RT_EOK;
+    rt_thread_t thread = RT_NULL;
+    
+    RT_ASSERT(param != RT_NULL);
+    RT_ASSERT(param->product_key[0] != RT_NULL);
+    RT_ASSERT(param->product_secret[0] != RT_NULL);
+    RT_ASSERT(param->mac[0] != RT_NULL);
+    RT_ASSERT(param->read_param_callback != RT_NULL);
+    RT_ASSERT(param->write_param_callback != RT_NULL);
+
+    memset(&con_param, 0, sizeof(con_param));
+    memcpy(&con_param, param, sizeof(con_param));
+
+    cloud = (cloud_st *)rt_malloc(sizeof(cloud_st));
+    if(RT_NULL == cloud)
+    {
+        gagent_err("malloc failed!\n");
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+    rt_memset(cloud, 0, sizeof(cloud_st));
+    cloud->con = &con;
+
+    lan = (lan_st *)rt_malloc(sizeof(lan_st));
+    if(RT_NULL == lan)
+    {
+        gagent_err("malloc failed!\n");
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+    memset(lan, 0, sizeof(lan_st));
+    lan->con = &con;
+
+    thread = rt_thread_create("gagent", 
+                                gagent_cloud_thread, 
+                                RT_NULL, 
+                                4096, 
+                                RT_THREAD_PRIORITY_MAX / 3, 
+                                20);
+    if(RT_NULL != thread)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rc = -RT_ERROR;
+        goto __exit;
+    }
+    
+    return rc;
+    
+__exit:
+    if(cloud != RT_NULL)
+        rt_free(cloud);
+
+    if(lan != RT_NULL)
+        rt_free(lan);
+        
+    return rc;    
+}

+ 67 - 0
gagent_cloud.h

@@ -0,0 +1,67 @@
+/*
+ * File      : gagent_cloud.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#ifndef __GAGENT_CLOUD_H__
+#define __GAGENT_CLOUD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define     PRODUCT_KEY_LEN             32
+#define     PRODUCT_SECERT_LEN          32
+#define     MAX_MAC_LEN                 32
+
+typedef struct
+{
+    char product_key[PRODUCT_KEY_LEN + 1];
+    char product_secret[PRODUCT_SECERT_LEN + 1];
+    char mac[MAX_MAC_LEN + 1];
+    int (*read_param_callback)(void *param, rt_uint32_t len);
+    int (*write_param_callback)(void *param, rt_uint32_t len);
+    int (*recv_packet_callback)(rt_uint8_t from, rt_uint8_t action, rt_uint8_t *kv, rt_uint16_t kv_len);
+} gagent_cloud_param;
+
+enum ATCTION_TYPE
+{
+    ACTION_CONTROL = 1,
+    ACTION_READ_STATUS = 2,
+    ACTION_READ_STATUS_ACK = 3,
+    ACTION_REPORT_STATUS = 4,
+    ACTION_TRANS_RECV = 5,
+    ACTION_TRANS_SEND = 6,
+    ACTION_PUSH_OTA = 254,	
+};
+
+int gagent_cloud_recv_packet(rt_uint8_t from, rt_uint8_t action, rt_uint8_t *kv, rt_uint16_t kv_len);
+
+int gagent_cloud_send_packet(rt_uint8_t action, rt_uint8_t *buf, rt_uint16_t buf_len);
+
+int gagent_cloud_start(gagent_cloud_param *param);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 172 - 0
gagent_def.h

@@ -0,0 +1,172 @@
+/*
+ * File      : gagent_def.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include <rtthread.h>
+#include <string.h>
+
+#include <lwip/sockets.h>
+#include "webclient.h"
+#include "paho_mqtt.h"
+
+#ifndef PKG_GAGENT_CLOUD_DEBUG
+#define PKG_GAGENT_CLOUD_DEBUG        1
+#endif
+
+#if (PKG_GAGENT_CLOUD_DEBUG == 1)
+#define     gagent_dbg            rt_kprintf("[gagent dbg:%d] %s ", __LINE__, __FUNCTION__);rt_kprintf
+#define     gagent_err            rt_kprintf("[gagent err:%d] %s ", __LINE__, __FUNCTION__);rt_kprintf
+#else
+#define     gagent_dbg(...)
+#define     gagent_err(...)
+#endif
+
+#define MAX_CLIENT			8
+
+
+#define BUF_LEN 				2048 
+
+#define HEAD_LEN                5       
+#define UDP_RECV_ERROR          199
+#define TCP_RECV_ERROR_BASE     100
+#define LOG_IP_BUF_LENGTH		16
+
+#define HARD_VERSION			"01RTT001"
+#define SOFT_VERSION			"04020020"
+
+
+#define G_SERVICE_DOMAIN 	"api.gizwits.com"
+#define G_SERVICE_PORT		"80"
+#define G_M2M_DOMAIN		"sandbox.gizwits.com"
+#define G_M2M_PORT			"1883"
+#define G_M2M_SSL_PORT		"8883"
+
+#define DID_LENGTH			22
+
+
+enum GAGENT_HARD_TYPE
+{
+    GAGENT_HARD_SOC = 1,
+    GAGENT_HARD_MCU = 2,
+};
+
+
+typedef struct _con_st	con_st;
+
+struct _con_st
+{
+    char	mac[32 + 1];
+    char	did[32 + 1];
+    char	passcode[16 + 1];
+    char	pk[48 + 1];
+    char	pk_secret[48 + 1];
+    char	hard_version[16 + 1];
+    char	soft_version[16 + 1];
+}; 
+
+
+typedef struct _cloud_st cloud_st;
+
+struct _cloud_st
+{
+	con_st		*con;
+    //
+	char mqtt_server[128];
+	int mqtt_port;
+	char sub_topic[2][128];
+	//
+	char recv_buf[BUF_LEN];
+	int recv_len;
+	char send_buf[BUF_LEN];
+	int send_len;
+    //
+	char ota_info[128];
+	int sn;
+};
+
+typedef struct _lan_st lan_st;
+
+struct _lan_st
+{
+	con_st	*con;
+	//
+	int	client_fd[MAX_CLIENT];
+    int tcp_server;
+    int udp_server;
+    struct sockaddr_in tcp_server_addr;
+    struct sockaddr_in udp_socket_addr;
+    struct sockaddr_in broadcast_to;
+
+    //local
+    int local_sock;
+    int local_port;
+    //
+	char recv_buf[BUF_LEN];
+	int	recv_len;
+	char send_buf[BUF_LEN];
+	int	send_len;
+	//
+	int	sn;
+};
+
+
+enum CMD_FROM_TYPE
+{
+    CMD_FROM_LAN = 0,
+    CMD_FROM_MQTT,
+};
+
+enum UDP_SEND_TYPE
+{
+    UDP_SEND_TYPE_DISCOVER = 0,
+    UDP_SEND_TYPE_BOARDCAST,
+};
+
+int gagent_add_pkcs(char *src, int len);
+
+uint16_t gagent_parse_rem_len(const uint8_t* buf);
+
+uint8_t gagent_num_rem_len_bytes(const uint8_t* buf);
+
+int gagent_get_one_packet(char *packet, int *data_len, rt_uint8_t *len_num, int remain_len);
+
+int gagent_set_one_packet(char *packet, uint8_t action, uint8_t *buf, uint32_t buf_len);
+
+uint8_t gagent_get_rem_len(int length, char *buf);
+
+int gagent_strtohex(char *pbDest, char *pbSrc, int nLen);
+
+int gagent_lan_send_packet(lan_st *lan, rt_uint8_t action, rt_uint8_t *buf, rt_uint16_t buf_len);
+
+int gagent_lan_init(lan_st *lan);
+
+int gagent_cloud_register(cloud_st *cloud);
+
+int gagent_cloud_provision(cloud_st *cloud);
+
+int gagent_cloud_check_ota(cloud_st *cloud);
+
+int gagent_mqtt_send_packet(cloud_st *cloud, rt_uint8_t action, rt_uint8_t *kv, rt_uint16_t kv_len);
+
+int gagent_mqtt_init(cloud_st *cloud);
+
+//#endif

+ 577 - 0
gagent_httpc.c

@@ -0,0 +1,577 @@
+/*
+ * File      : gagent_httpc.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include "gagent_def.h"
+#include "aes.h"
+
+#define     MAX_HTTPC_URL_LEN           1024
+#define     MAX_HTTPC_RECV_LEN          2048
+
+struct cloud_httpc
+{
+    char *recv_buf;
+    int recv_len;
+};
+
+static struct cloud_httpc httpc;
+
+typedef int (*WEBCLIENT_CUSTOM_RESPONSE_CB)(size_t total, size_t offset, char *from, size_t from_len);
+
+
+static int webclient_common(int method, const char *URI, 
+                            const char * data, size_t data_sz,
+                            WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
+{
+    struct webclient_session *session = RT_NULL;
+    char *header = RT_NULL, *header_ptr;
+    size_t header_sz = 0;
+    int rc = WEBCLIENT_OK;
+    int length = 0;
+    size_t total = 0, offset = 0;
+    
+    rt_uint8_t *buffer = RT_NULL;
+
+    header = (char *)rt_malloc(WEBCLIENT_HEADER_BUFSZ);
+    if(RT_NULL == header)
+    {
+        gagent_err("malloc failed!\n");
+        rc = -WEBCLIENT_NOMEM;
+        goto __exit;
+    }
+    rt_memset(header, 0, WEBCLIENT_HEADER_BUFSZ);
+
+    header_ptr = header;
+    header_ptr += rt_snprintf(header_ptr,
+                            WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
+                            "Content-Type: application/x-www-form-urlencoded;charset:UTF-8\r\n");
+                
+    if(data)
+    {
+        header_ptr += rt_snprintf(header_ptr, 
+                                WEBCLIENT_HEADER_BUFSZ - (header_ptr - header), 
+                                "Content-Length:%d\r\n", strlen(data));
+    }
+                            
+    header_sz = header_ptr - header;
+    session = webclient_open_custom(URI, method, header, header_sz, data, data_sz);
+    if(RT_NULL == session)
+    {
+        gagent_err("webclient_open_custom failed!\n");
+        rc = -WEBCLIENT_OK;
+        goto __exit;
+    }
+    gagent_dbg("response:%d\n",session->response);
+
+    buffer = (rt_uint8_t *)rt_malloc(WEBCLIENT_RESPONSE_BUFSZ);
+    if(RT_NULL == buffer)
+    {
+        gagent_err("malloc failed!\n");
+        rc = -WEBCLIENT_NOMEM;
+        goto __exit;
+    }
+
+    if(session->chunk_sz > 0)
+    {
+        gagent_dbg("chunk_sz:%d\n", session->chunk_sz);
+        total = session->chunk_sz;
+   }
+    else if(session->content_length > 0)
+    {
+        gagent_dbg("content_length:%d content_length_remainder:%d\n", session->content_length, session->content_length_remainder);
+        total = session->content_length;
+    }
+    
+    while(total != offset)
+    {
+        memset(buffer, 0, WEBCLIENT_RESPONSE_BUFSZ);
+        length = webclient_read(session, buffer, WEBCLIENT_RESPONSE_BUFSZ);
+        if(length <= 0)
+        {
+            rc = length;
+            break;
+        }
+        
+        if(webclient_custom_response_cb)
+            webclient_custom_response_cb(total, offset, (char *)buffer, (int)length);
+
+        offset += length;
+    }
+
+__exit:
+    if(RT_NULL != buffer)
+    {
+        rt_free(buffer);
+        buffer = RT_NULL;
+    }
+
+    if(RT_NULL != header)
+    {
+        rt_free(header);
+        header = RT_NULL;
+    }
+
+    if(RT_NULL != session)
+    {
+        webclient_close(session);
+        session = RT_NULL;
+    }
+    return rc; 
+}
+
+int webclient_get(const char *URI, WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
+{
+    return webclient_common(WEBCLIENT_GET, URI, NULL, 0, webclient_custom_response_cb);
+}
+
+int webclient_post(const char *URI, const char * data, size_t data_sz,
+                            WEBCLIENT_CUSTOM_RESPONSE_CB webclient_custom_response_cb)
+{
+    return webclient_common(WEBCLIENT_POST, URI, data, data_sz, webclient_custom_response_cb);
+}
+
+int gagent_cloud_httpc_cb(size_t total, size_t offset, char *from, size_t from_len)
+{
+    extern cloud_st *cloud;
+    
+    gagent_dbg("total:%d offset:%d len:%d\n", total, offset, from_len);
+    gagent_dbg("buf:%s\n", from);
+    
+    rt_memset(httpc.recv_buf, 0, MAX_HTTPC_RECV_LEN);
+    rt_memcpy(httpc.recv_buf, from, from_len);
+    httpc.recv_len = from_len;
+
+    return RT_EOK;
+}
+
+int gagent_cloud_register(cloud_st *cloud)
+{
+    int rc = RT_EOK;
+    int content_len, aes_len, i;
+    //
+    char *content = RT_NULL;
+    char *url = RT_NULL;
+    char *ptr = RT_NULL;
+    
+    uint8_t aes_key[16];
+    char *aes_buf = RT_NULL;
+    aes_context *aes_ctx = RT_NULL;
+
+    content = (char *)rt_malloc(256);
+    if(RT_NULL == content)
+    {
+        gagent_err("malloc faield!\n");
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    aes_buf = (char *)rt_malloc(256);
+    if(RT_NULL == aes_buf)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    //data
+    rt_memset(content, 0, 256);
+    rt_snprintf((char *)content, 256, "mac=%02x%02x%02x%02x%02x%02x&passcode=%s&type=%s", \
+                cloud->con->mac[0], cloud->con->mac[1], cloud->con->mac[2], cloud->con->mac[3], cloud->con->mac[4], cloud->con->mac[5], \
+                cloud->con->passcode, "normal");
+
+    content_len = strlen(content);
+
+    rt_memset(aes_key, 0, sizeof(aes_key));
+    gagent_strtohex((char *)aes_key, cloud->con->pk_secret, strlen(cloud->con->pk_secret) > 32 ? 32 : strlen(cloud->con->pk_secret));
+    gagent_dbg("content:%s, pk_secret:%s\n", content, cloud->con->pk_secret);
+
+    aes_ctx = (aes_context *)rt_malloc(sizeof(aes_context));
+    if(RT_NULL == aes_ctx)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    rt_memset(aes_ctx, 0, sizeof(aes_context));
+    aes_setkey_enc(aes_ctx, aes_key, 128);
+    //
+    rt_memset(aes_buf, 0, 256);
+    
+    content_len = strlen(content);
+    if(content_len % 16)
+        content_len = gagent_add_pkcs(content, content_len);
+    
+    aes_len = 0;
+    for(i = 0; i < content_len; i += 16)
+    {
+        aes_crypt_ecb(aes_ctx, AES_ENCRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
+        aes_len += 16;
+    }
+
+    ptr = content;
+    rt_memset(ptr, 0, 256);
+    
+    strcpy(ptr, "data=");
+    ptr += strlen("data=");
+    
+    if(aes_len > 0)
+    {
+        for(i = 0; i < aes_len; i ++)
+        {
+            ptr += rt_snprintf(ptr, 256 - (ptr - content), "%02x", aes_buf[i]);
+        }
+    }
+
+    gagent_dbg("content:%s\n", content);
+    
+    url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
+    if(RT_NULL == url)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    ptr = url;
+    memset(ptr, 0, MAX_HTTPC_URL_LEN);
+    
+    //url
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/%s/device", cloud->con->pk);
+    
+    gagent_dbg("url:%s\n", url);
+
+    httpc.recv_buf = RT_NULL;
+    httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
+    if(RT_NULL == httpc.recv_buf)
+    {
+       rc = -RT_ENOMEM;
+       goto __exit;
+    }
+    
+    rc = webclient_post((const char *)url, (const char *)content, strlen(content), gagent_cloud_httpc_cb);
+    if(rc != RT_EOK)
+    {
+        gagent_err("weblient_post failed!\n");
+        goto __exit;
+    }
+
+    //
+    rt_memset(content, 0, 256);
+    aes_len = gagent_strtohex((char *)content, (char *)httpc.recv_buf, httpc.recv_len);
+
+    rt_memset(aes_ctx, 0, sizeof(aes_context));
+    aes_setkey_dec(aes_ctx, aes_key, 128);
+    
+    rt_memset(aes_buf, 0, 256);
+    for(i = 0; i < aes_len; i += 16)
+        aes_crypt_ecb(aes_ctx, AES_DECRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
+
+    gagent_dbg("%s\n", aes_buf);
+
+    if(strstr(aes_buf, "did=") != NULL)
+        rt_memcpy(cloud->con->did, aes_buf + strlen("did="), DID_LENGTH);
+    
+__exit:
+    if(RT_NULL != httpc.recv_buf)
+    {
+        rt_free(httpc.recv_buf);
+        httpc.recv_buf = RT_NULL;
+    }
+    
+    if(RT_NULL != url)
+    {
+        rt_free(url);
+        url = RT_NULL;
+    }
+
+    if(RT_NULL != aes_ctx)
+    {
+        rt_free(aes_ctx);
+        aes_ctx = RT_NULL;
+    }
+
+    if(RT_NULL != aes_buf)
+    {
+        rt_free(aes_buf);
+        aes_buf = RT_NULL;
+    }
+    
+    if(RT_NULL != content)
+    {
+        rt_free(content);
+        content = RT_NULL;
+    }
+
+    return rc;
+}
+
+int gagent_cloud_provision(cloud_st *cloud)
+{
+    int rc = RT_EOK;
+    int content_len, aes_len, i;
+    
+    char *url = RT_NULL;
+    char *content = RT_NULL;
+    char *ptr = RT_NULL;
+    char *ptr_tail = RT_NULL;
+
+    char aes_key[16];
+    char *aes_buf = RT_NULL;
+    aes_context *aes_ctx = RT_NULL;
+    
+    content = (char *)rt_malloc(256);
+    if(RT_NULL == content)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+    
+    aes_buf = (char *)rt_malloc(256);
+    if(RT_NULL == aes_buf)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    //data    
+    rt_memset(content, 0, 256);
+    strcpy(content, cloud->con->did);
+
+    rt_memset(aes_key, 0, sizeof(aes_key));
+    gagent_strtohex((char *)aes_key, cloud->con->pk_secret, strlen(cloud->con->pk_secret) > 32 ? 32 : strlen(cloud->con->pk_secret));
+
+    gagent_dbg("content:%s, pk_secret:%s\n", content, cloud->con->pk_secret);
+
+    aes_ctx = (aes_context *)rt_malloc(sizeof(aes_context));
+    if(RT_NULL == aes_ctx)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    rt_memset(aes_ctx, 0, sizeof(aes_context));
+    aes_setkey_enc(aes_ctx, (uint8_t *)aes_key, 128);
+    //
+    rt_memset(aes_buf, 0, 256);
+
+    content_len = strlen(content);
+    if(content_len % 16)
+        content_len = gagent_add_pkcs(content, content_len);
+
+    aes_len = 0;
+    for(i = 0; i < content_len; i += 16)
+    {
+        aes_crypt_ecb(aes_ctx, AES_ENCRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
+        aes_len += 16;
+    }
+
+    ptr = content;
+    if(aes_len > 0)
+    {
+        for(i = 0; i < aes_len; i ++)
+        {
+            ptr += rt_snprintf(ptr, 256 - (ptr - content), "%02x", aes_buf[i]);
+        }
+    }
+    gagent_dbg("content:%s\n", content);
+
+    url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
+    if(RT_NULL == url)
+    {
+        rc = -RT_ENOMEM;
+        return rc;
+    }
+
+    ptr = url;
+    rt_memset(url, 0, MAX_HTTPC_URL_LEN);
+    
+    //url
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/%s/device?", cloud->con->pk);
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "did=%s", content);
+    gagent_dbg("url:%s\n", url);
+    
+    //
+    rt_memset(cloud->mqtt_server, 0, sizeof(cloud->mqtt_server));
+    rt_memcpy(cloud->mqtt_server, G_M2M_DOMAIN, sizeof(G_M2M_DOMAIN));
+    //
+    cloud->mqtt_port = 0;
+    cloud->mqtt_port = atoi(G_M2M_PORT);
+
+    httpc.recv_buf = RT_NULL;
+    httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
+    if(RT_NULL == httpc.recv_buf)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+    
+    rc = webclient_get((const char *)url, gagent_cloud_httpc_cb);
+    if(rc != RT_EOK)
+    {
+        rt_kprintf("weblient_post failed!\n");
+        goto __exit;
+    }
+    
+    rt_memset(content, 0, 256);
+    aes_len = gagent_strtohex(content, httpc.recv_buf, httpc.recv_len);
+
+    rt_memset(aes_ctx, 0, sizeof(aes_context));
+    aes_setkey_dec(aes_ctx, (uint8_t *)aes_key, 128);
+    
+    rt_memset(aes_buf, 0, 256);
+    for(i = 0; i < aes_len; i += 16)
+        aes_crypt_ecb(aes_ctx, AES_DECRYPT, (uint8_t *)content + i, (uint8_t *)aes_buf + i);
+
+    gagent_dbg("%s\n", aes_buf);
+
+    //mqtt_server
+    ptr = strstr(aes_buf, "host=");
+    if(ptr > 0)
+    {
+        ptr += strlen("host=");
+        ptr_tail = strchr(ptr, '&');
+        if(ptr_tail > 0)
+        {
+            rt_memset(cloud->mqtt_server, 0, sizeof(cloud->mqtt_server));
+            rt_memcpy(cloud->mqtt_server, ptr, (ptr_tail - ptr));
+        }
+    }
+
+    //mqtt_port
+    ptr = strstr(aes_buf, "port=");
+    if(ptr > 0)
+    {
+        ptr += strlen("port=");
+
+        ptr_tail = strchr(ptr, '&');
+        if(ptr_tail > 0)
+        {
+            *ptr_tail = '\0';
+            
+            cloud->mqtt_port = 0;
+            cloud->mqtt_port = atoi(ptr);
+        }
+    }
+
+    gagent_dbg("mqtt_server:%s port:%d\n", cloud->mqtt_server, cloud->mqtt_port);
+
+__exit:
+    if(RT_NULL != httpc.recv_buf)
+    {
+        rt_free(httpc.recv_buf);
+        httpc.recv_buf = RT_NULL;
+    }
+    
+    if(RT_NULL != url)
+    {
+        rt_free(url);
+        url = RT_NULL;
+    }
+
+    if(RT_NULL != aes_ctx)
+    {
+        rt_free(aes_ctx);
+        aes_ctx = RT_NULL;
+    }
+
+    if(RT_NULL != aes_buf)
+    {
+        rt_free(aes_buf);
+        aes_buf = RT_NULL;
+    }
+    
+    if(RT_NULL != content)
+    {
+        rt_free(content);
+        content = RT_NULL;
+    }
+
+    return rc;
+}
+
+
+int gagent_cloud_check_ota(cloud_st *cloud)
+{
+    int rc = RT_EOK;
+    char *url = RT_NULL;
+    char *content = RT_NULL;
+    char *ptr = RT_NULL;
+    
+    content = (char *)rt_malloc(256);
+    if(RT_NULL == content)
+    {
+        gagent_err("malloc faield!\n");
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    //data
+    rt_memset(content, 0, 256);
+    rt_snprintf((char *)content, 256, "passcode=%s&type=%d&hard_version=%s&soft_version=%s", \
+               cloud->con->passcode, GAGENT_HARD_SOC, cloud->con->hard_version, cloud->con->soft_version);
+
+    gagent_dbg("content:%s\n", content);
+
+    url = (char *)rt_malloc(MAX_HTTPC_URL_LEN);
+    if(RT_NULL == url)
+    {
+        rc = -RT_ENOMEM;
+        return rc;
+    }
+
+    ptr = url;
+    rt_memset(url, 0, MAX_HTTPC_URL_LEN);
+    
+    //url
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "http://%s:%s", G_SERVICE_DOMAIN, G_SERVICE_PORT);
+    ptr += rt_snprintf(ptr, MAX_HTTPC_URL_LEN - (ptr - url), "/dev/ota/v4.1/update_and_check/%s", cloud->con->did);
+    
+    gagent_dbg("url:%s\n", url);
+
+    httpc.recv_buf = RT_NULL;
+    httpc.recv_buf = (char *)rt_malloc(MAX_HTTPC_RECV_LEN);
+    if(RT_NULL != httpc.recv_buf)
+    {
+        rc = -RT_ENOMEM;
+        goto __exit;
+    }
+
+    rc = webclient_post((const char *)url, (const char *)content, strlen(content), gagent_cloud_httpc_cb);
+    if(rc != RT_EOK)
+    {
+        gagent_err("weblient_post failed!\n");
+        goto __exit;
+    }
+    
+__exit:
+    if(RT_NULL != httpc.recv_buf)
+        rt_free(httpc.recv_buf);
+
+    if(RT_NULL != url)
+        rt_free(url);
+
+    if(RT_NULL != content)
+        rt_free(content);
+
+    return rc;
+}
+

+ 940 - 0
gagent_lan.c

@@ -0,0 +1,940 @@
+/*
+ * File      : gagent_lan.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include "gagent_def.h"
+#include "gagent_cloud.h"
+
+#include <lwip/netifapi.h>
+
+
+#if !defined(LWIP_NETIF_LOOPBACK) || (LWIP_NETIF_LOOPBACK == 0)
+#error "must enable (LWIP_NETIF_LOOPBACK = 1) for publish!"
+#endif /* LWIP_NETIF_LOOPBACK */
+
+#define     GAGENT_CLOUD_UDP_PORT           12414
+#define     GAGENT_CLOUD_TCP_PORT           12416
+#define     GAGENT_CLOUD_BROADCAST          2415
+
+#define     GAGENT_LAN_TIMEOUT              5           //sec
+
+static rt_thread_t lan_thread;
+static int local_port = 7100;
+
+#if (PKG_GAGENT_CLOUD_DEBUG == 1)
+#define     LAN_RECV_DEBUG
+#define     LAN_SEND_DEBUG
+#endif
+
+
+static int lan_send_device_info(lan_st *lan, rt_uint8_t send_type)
+{
+    char *index, *len_index;
+    
+    memset(lan->send_buf, 0, sizeof(lan->send_buf));
+
+    index = lan->send_buf;
+
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //len
+//    *index ++ = 0x0a;
+    len_index = index;
+    index ++;
+
+    //flag
+    *index ++ = 0x00;
+
+    //cmd
+    *index ++ = 0x00;
+    if(send_type == UDP_SEND_TYPE_DISCOVER)
+        *index ++ = 0x04;
+    else if(send_type == UDP_SEND_TYPE_BOARDCAST)
+        *index ++ = 0x05;
+
+    //did_len
+    *index ++ = 0x00;
+    *index ++ = strlen(lan->con->did);
+    //did
+    memcpy(index, lan->con->did, 0x16);
+    index += strlen(lan->con->did);
+    
+    //mac_len
+    *index ++ = 0x00;
+    *index ++ = 0x06;
+    //mac
+    memcpy(index, lan->con->mac, 0x06);
+    index += 0x06;
+
+    //hard_version_len
+    *index ++ = 0x00;
+    *index ++ = strlen(lan->con->soft_version);
+    //soft_version
+    memcpy(index, lan->con->soft_version, strlen(lan->con->soft_version));
+    index += strlen(lan->con->soft_version);
+
+    //pk_len
+    *index ++ = 0x00;
+    *index ++ = strlen(lan->con->pk);
+    //pk
+    memcpy(index, lan->con->pk, strlen(lan->con->pk));
+    index += strlen(lan->con->pk);
+
+    index += 8;
+
+    lan->send_len = index - lan->send_buf;
+    *len_index = lan->send_len - HEAD_LEN;
+    
+    return RT_EOK;
+}
+
+
+static int lan_udp_do_packet(lan_st *lan)
+{
+    char *one_packet;
+    int data_len;
+    rt_uint8_t len_num;
+    short cmd;
+    int rc = RT_EOK;
+
+    one_packet = lan->recv_buf;
+    while(gagent_get_one_packet(one_packet, &data_len, &len_num, lan->recv_len) == 0)
+    {   
+        rc = RT_EOK;
+
+        memcpy(&cmd, one_packet + 6, 2);
+        cmd = ntohs(cmd);
+        
+        gagent_dbg("cmd:%d\n", cmd);
+        
+        switch(cmd)
+        {
+            case 0x03:
+                rc = lan_send_device_info(lan, UDP_SEND_TYPE_DISCOVER);
+            break;
+        }
+    
+        one_packet += (data_len + len_num + HEAD_LEN);
+        lan->recv_len -= (data_len + len_num + HEAD_LEN);
+        
+        if(rc != 0)
+            return rc;
+    }
+
+    return rc;
+}
+
+static int lan_get_passcode(lan_st *lan)
+{
+    char *index, *len_index;
+
+    index = lan->send_buf;
+
+    memset(index, 0, sizeof(lan->send_buf));
+
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //len
+    len_index = index;
+    index ++;
+
+    //flag
+    *index ++ = 0x00;
+    
+    //cmd
+    *index ++ = 0x00;
+    *index ++ = 0x07;
+
+    //passcode_len
+    *index ++ = 0x00;
+    *index ++ = strlen(lan->con->passcode);
+
+    memcpy(index, lan->con->passcode, strlen(lan->con->passcode));
+    index += strlen(lan->con->passcode);
+
+    //
+    lan->send_len = (index - lan->send_buf);
+    *len_index = lan->send_len - HEAD_LEN;
+    
+    return RT_EOK;
+}
+
+static int lan_get_device_info(lan_st *lan)
+{
+    char *index, *len_index;
+
+    index = lan->send_buf;
+
+    memset(index, 0, sizeof(lan->send_buf));
+
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //len
+    len_index = index;
+    index ++;
+
+    //flag
+    *index ++ = 0x00;
+    
+    //cmd
+    *index ++ = 0x00;
+    *index ++ = 0x14;
+
+    //hard_version
+    memcpy(index, lan->con->hard_version, strlen(lan->con->hard_version));
+    index += 8;
+
+    //soft_version
+    memcpy(index, lan->con->soft_version, strlen(lan->con->soft_version));
+    index += 8;
+
+    //mcu_hard
+    index += 8;
+
+    //mcu_soft_version
+    index += 8;
+
+	//p0 version
+	index += 8;
+
+	//remain1
+	index += 8;
+
+    //remain2_len
+	*index ++ = 0x00;
+	*index ++ = 0x00;
+
+	//pk_len
+    *index ++ = 0x00;
+    *index ++ = strlen(lan->con->pk);
+
+    //pk
+    memcpy(index, lan->con->pk, strlen(lan->con->pk));
+    index += strlen(lan->con->pk);
+	
+    lan->send_len = (index - lan->send_buf);
+    *len_index = lan->send_len - HEAD_LEN;
+    
+    return RT_EOK;
+}
+
+static int lan_login_device(lan_st *lan, char *packet)
+{
+    char *index, *len_index;
+    char passcode_recv[32];
+    uint16_t passcode_len;
+
+    memcpy(&passcode_len, packet + HEAD_LEN + 1 + 2, 2);
+    passcode_len = ntohs(passcode_len);
+
+    memset(passcode_recv, 0x00, sizeof(passcode_recv));
+    memcpy(passcode_recv, packet + HEAD_LEN + 1 + 2 + 2, passcode_len);
+        
+    index = lan->send_buf;
+
+    memset(index, 0, sizeof(lan->send_buf));
+
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //len
+    len_index = index;
+    index ++;
+
+    //flag
+    *index ++ = 0x00;
+
+    //cmd
+    *index ++ = 0x00;
+    *index ++ = 0x09;
+
+    //result
+    if(strncmp(lan->con->passcode, passcode_recv, passcode_len) == 0)
+        *index ++ = 0x00;
+    else
+        *index ++ = 0x01;
+
+    lan->send_len = index - lan->send_buf;
+    *len_index = lan->send_len - HEAD_LEN;
+
+    return RT_EOK;
+}
+
+
+static int lan_trans_data(lan_st *lan, char *packet)
+{
+    uint16_t len, cmd;
+    char *index, *kv;
+    uint16_t kv_len;
+    uint8_t length_len, action;
+
+    lan->send_len = 0;
+    //
+    action = 0;
+    kv_len = 0;
+    kv = 0;
+    
+    index = packet;
+	len = gagent_parse_rem_len((const uint8_t *)index + 4);
+	length_len = gagent_num_rem_len_bytes((const uint8_t*)index + 4);
+
+    index += (HEAD_LEN + length_len);
+    
+    rt_memcpy(&cmd, index, 2);
+    index += 2;
+
+    cmd = ntohs(cmd);
+    gagent_dbg("cmd:%0x\n", cmd);
+    
+	// 00 00 00 03 06 00 00 90 01 01 01 
+	// 00 00 00 03 0A 00 00 93 00 00 00 00 01 01 01 
+    if(cmd == 0x90)
+    {
+        action = *index ++;
+        kv =  index;
+        kv_len = len - 4;
+        lan->sn = -1;
+    }
+    else if(cmd == 0x93)
+    {
+        memcpy(&lan->sn, index, 4);
+        index += 4;
+        gagent_dbg("lan_sn:%d\n", lan->sn);
+        
+        action = *index ++;
+        kv = index;
+        kv_len = len - 8;
+    }
+    else
+        return -RT_ERROR;
+    
+    return gagent_cloud_recv_packet(CMD_FROM_LAN, action, (uint8_t *)kv, kv_len);
+}
+
+static int lan_heart_beat(lan_st *lan)
+{
+    char *index, *len_index;
+
+    index = lan->send_buf;
+
+    memset(index, 0, sizeof(lan->send_buf));
+
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //len
+    len_index = index;
+    index ++;
+
+    //flag
+    *index ++ = 0x00;
+
+    //cmd
+    *index ++ = 0x00;
+    *index ++ = 0x16;
+
+    lan->send_len = index - lan->send_buf;
+    *len_index = lan->send_len - HEAD_LEN;
+
+    return RT_EOK;
+}
+
+static int lan_tcp_do_packet(lan_st *lan)
+{
+    char *one_packet;
+    rt_uint32_t data_len;
+    rt_uint8_t len_num;
+    rt_uint16_t cmd;
+    int rc = RT_EOK;
+
+    one_packet = lan->recv_buf;
+    while(gagent_get_one_packet(one_packet, (int *)&data_len, &len_num, lan->recv_len) == RT_EOK)
+    {   
+        rc = RT_EOK;
+
+        memcpy(&cmd, one_packet + 6, 2);
+        cmd = ntohs(cmd);
+
+        gagent_dbg("lan_cmd:%x\n",cmd);
+        switch(cmd)
+        {
+            case 0x06:
+                rc = lan_get_passcode(lan);
+            break;
+
+            case 0x08:
+                rc = lan_login_device(lan, one_packet);
+            break;
+
+            case 0x90:
+            case 0x93:
+                rc = lan_trans_data(lan, one_packet);
+            break;
+
+            case 0x13:
+                rc = lan_get_device_info(lan);
+            break;
+
+            case 0x15:
+                rc = lan_heart_beat(lan);
+            break;
+
+            default:
+            break;
+        }
+
+        one_packet += (data_len + len_num + HEAD_LEN);
+        lan->recv_len -= (data_len + len_num + HEAD_LEN);
+        
+        if(rc != 0)
+            return rc;
+    }
+
+    return rc;
+}
+
+static int gagent_create_tcp_socket(lan_st *lan)
+{
+    int rc = RT_EOK;
+    int opt;
+
+    if(lan->tcp_server != -1)
+        return RT_EOK;
+        
+    lan->tcp_server = lwip_socket(AF_INET, SOCK_STREAM, 0);
+    if(lan->tcp_server < 0)
+    {
+        gagent_err("tcp socket create failed!\n");
+        return -RT_ERROR;
+    }
+    
+    lan->tcp_server_addr.sin_family = AF_INET;
+    lan->tcp_server_addr.sin_port = htons(GAGENT_CLOUD_TCP_PORT);
+    lan->tcp_server_addr.sin_addr.s_addr = INADDR_ANY;
+    memset(&lan->tcp_server_addr.sin_zero, 0, sizeof(lan->tcp_server_addr.sin_zero));
+        
+    opt = 1;
+    setsockopt(lan->tcp_server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+    
+    rc = lwip_bind(lan->tcp_server, (struct sockaddr *)&lan->tcp_server_addr, (socklen_t)sizeof(lan->tcp_server_addr));
+    if(rc < 0)
+    {
+        gagent_err("tcp socket bind failed! errno:%d\n", errno);
+        lwip_close(lan->tcp_server);
+        return -RT_ERROR;
+    }
+    
+    rc = lwip_listen(lan->tcp_server, MAX_CLIENT);
+    if(rc < 0)
+    {
+        gagent_err("tcp socket listen failed! errno:%d\n", errno);
+        lwip_close(lan->tcp_server);
+        return -RT_ERROR;
+    }
+
+
+    return RT_EOK;
+}
+
+
+static int gagent_create_udp_socket(lan_st *lan)
+{
+    int opt;
+    int broadcast;
+
+    if(lan->udp_server != -1)
+        return RT_EOK;
+        
+    lan->udp_server = lwip_socket(AF_INET, SOCK_DGRAM, 0);
+    if(lan->udp_server < 0)
+    {
+        gagent_err("udp socket create failed!\n");
+        return -RT_ERROR;
+    }
+
+    rt_memset(&lan->udp_socket_addr, 0, sizeof(lan->udp_socket_addr));
+    lan->udp_socket_addr.sin_family = AF_INET;
+    lan->udp_socket_addr.sin_port = htons(GAGENT_CLOUD_UDP_PORT);
+    lan->udp_socket_addr.sin_addr.s_addr = INADDR_ANY;
+
+    opt = 1;
+    lwip_setsockopt(lan->udp_server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+    broadcast = 1;
+    lwip_setsockopt(lan->udp_server, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast));
+
+    if(lwip_bind(lan->udp_server, (struct sockaddr *)&lan->udp_socket_addr, (socklen_t)sizeof(lan->udp_socket_addr)) < 0)
+    {
+        gagent_err("udp socket bind failed! errno:%d\n", errno);
+        lwip_close(lan->udp_server);
+        return -RT_ERROR;
+    }
+
+    rt_memset(&lan->broadcast_to, 0, sizeof(lan->broadcast_to));
+    lan->broadcast_to.sin_family = AF_INET;
+    lan->broadcast_to.sin_port = htons(GAGENT_CLOUD_BROADCAST);
+    lan->broadcast_to.sin_addr.s_addr = inet_addr("255.255.255.255");
+    
+    return RT_EOK;
+}
+
+static int gagent_create_localudp_socket(lan_st *lan)
+{
+    struct sockaddr_in local_udp_server;
+    
+    if(lan->local_sock != -1)
+        return RT_EOK;
+
+    lan->local_sock = lwip_socket(AF_INET, SOCK_DGRAM, 0);
+    if(lan->local_sock < 0)
+    {
+        gagent_err("local udp socket create failed!\n");
+        return -RT_ERROR;
+    }
+
+    memset(&local_udp_server, 0, sizeof(local_udp_server));
+    local_udp_server.sin_family = AF_INET;
+    local_udp_server.sin_port = htons(local_port);
+    local_udp_server.sin_addr.s_addr = INADDR_ANY;
+
+    if(lwip_bind(lan->local_sock, (struct sockaddr *)&local_udp_server, sizeof(local_udp_server)) < 0)
+    {
+        gagent_err("local udp socket bind failed!\n");
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+static int gagent_close_tcp_socket(lan_st *lan)
+{
+    if(lan->tcp_server != -1)
+    {
+        lwip_close(lan->tcp_server);
+        lan->tcp_server = -1;
+    }
+    
+    return RT_EOK;
+}
+
+static int gagent_close_udp_socket(lan_st *lan)
+{
+    if(lan->udp_server != -1)
+    {
+        lwip_close(lan->udp_server);
+        lan->udp_server = -1;
+    }
+
+    return RT_EOK;
+}
+
+static int gagent_close_localudp_socket(lan_st *lan)
+{
+    if(lan->local_sock != -1)
+    {
+        lwip_close(lan->local_sock);
+        lan->local_sock = -1;
+    }
+
+    return RT_EOK;
+}
+
+void gagent_lan_thread(void *parameter)
+{
+    lan_st *lan = (lan_st *)parameter;
+    int rc = RT_EOK;
+    fd_set readfds;
+    int maxfd;
+    uint8_t id;
+    struct timeval timeout;
+    int client_sock;
+    struct sockaddr_in client_addr;
+    int addr_len = sizeof(client_addr);
+    uint8_t tcp_client_count = 0;
+
+    RT_ASSERT(lan != RT_NULL);
+
+    lan->tcp_server = -1;
+    lan->udp_server = -1;
+    lan->local_sock = -1;
+    
+    while(1)
+    {
+        if(gagent_create_tcp_socket(lan) < 0)
+        {
+            rt_thread_delay(rt_tick_from_millisecond(3000));
+            continue;
+        }
+
+        if(gagent_create_udp_socket(lan) < 0)
+        {
+            rt_thread_delay(rt_tick_from_millisecond(3000));
+            continue;
+        }
+
+				if(gagent_create_localudp_socket(lan) < 0)
+        {
+            rt_thread_delay(rt_tick_from_millisecond(3000));
+            continue;
+        }
+        
+        for(id = 0; id < MAX_CLIENT; id ++)
+				{
+            lan->client_fd[id] = -1;
+        } 
+        
+        while(1)
+        {
+            FD_ZERO(&readfds);
+            FD_SET(lan->tcp_server, &readfds);
+            FD_SET(lan->udp_server, &readfds);
+            FD_SET(lan->local_sock, &readfds);
+            
+            maxfd = lan->tcp_server;
+            if(lan->udp_server > maxfd)
+                maxfd = lan->udp_server;
+
+            if(lan->local_sock > maxfd)
+                maxfd = lan->local_sock;
+            
+            for(id = 0; id < MAX_CLIENT; id ++)
+            {
+                if(lan->client_fd[id] == -1)
+                    continue;
+
+                FD_SET(lan->client_fd[id], &readfds);
+                if(lan->client_fd[id] > maxfd)
+                    maxfd = lan->client_fd[id];
+            }
+
+            timeout.tv_sec = GAGENT_LAN_TIMEOUT;
+            timeout.tv_usec = 0;
+
+            rc = lwip_select(maxfd + 1, &readfds, 0, 0, &timeout);
+            if(rc < 0)
+            {
+               gagent_err("socket select failed!\n");
+                break;
+            }
+            else if(rc == 0)
+            {
+                if(tcp_client_count >= MAX_CLIENT)
+                    continue;
+                    
+                //broadcast    
+                rc = lan_send_device_info(lan, UDP_SEND_TYPE_BOARDCAST);
+                if(rc == RT_EOK && lan->send_len > 0)
+                {
+                    rc = lwip_sendto(lan->udp_server, lan->send_buf, lan->send_len, 0,
+                                    (struct sockaddr *)&lan->broadcast_to, (socklen_t)sizeof(lan->broadcast_to));
+                    if(rc <= 0)
+                    {
+                        gagent_err("udp socket broadcast failed! errno:%d\n", errno);
+                        break;
+                    }
+                 }   
+
+                continue;
+            }
+
+            //local
+            if(FD_ISSET(lan->local_sock, &readfds))
+            {
+                //locak socket can read
+                struct sockaddr_in local_client_addr;
+                int addr_len = sizeof(local_client_addr);
+                rt_uint8_t i;
+                
+                lan->recv_len = lwip_recvfrom(lan->local_sock, lan->recv_buf, sizeof(lan->recv_buf), 0,
+                                                (struct sockaddr *)&local_client_addr, (socklen_t *)&addr_len);
+                if(local_client_addr.sin_addr.s_addr != *(uint32_t *)&netif_default->ip_addr)
+                {
+                    continue;
+                }
+
+                if(lan->recv_len <= 0)
+                {
+                    gagent_err("local udp socket recvfrom failed!\n");
+                    continue;
+                }
+
+                for(i = 0; i < MAX_CLIENT; i ++)
+                {
+                    if(lan->client_fd[i] == -1)
+                        continue;
+
+                    rc = lwip_send(lan->client_fd[i], lan->recv_buf, lan->recv_len, 0);
+                    if(rc <= 0)
+                    {
+                        gagent_err("send clnt %d failed! errno:%d\n", i, errno);
+                        lwip_close(lan->client_fd[i]);
+                        lan->client_fd[i] = -1;
+                        if(tcp_client_count > 0)
+                            tcp_client_count --;
+                    }
+                    gagent_dbg("send client send len:%d\n", rc);
+                }
+            }
+
+            if(FD_ISSET(lan->udp_server, &readfds))
+            {
+                //udp socket can read
+                addr_len = sizeof(client_addr);
+                lan->recv_len = lwip_recvfrom(lan->udp_server, lan->recv_buf, sizeof(lan->recv_buf), 0,
+                                                (struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
+                if(lan->recv_len <= 0)
+                {
+                    gagent_err("udp socket recv from failed! errno:%d\n", errno);
+                    break;
+                }
+                
+#ifdef LAN_RECV_DEBUG
+                {
+                    int i;
+                    gagent_dbg("udp client:%s port:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
+                    rt_kprintf("recv len:%d ", lan->recv_len);
+                    for(i = 0; i < lan->recv_len; i ++)
+                    {
+                        rt_kprintf("%02x ", lan->recv_buf[i]);
+                    }
+                    rt_kprintf("\r\n");
+                }
+#endif
+                rc = lan_udp_do_packet(lan);
+                if(rc == RT_EOK && lan->send_len > 0)
+                {
+#ifdef LAN_RECV_DEBUG
+                    gagent_dbg("udp client:%d send_len:%d\n", id, lan->send_len);
+                    {
+                        int t;
+                        for(t = 0; t < lan->send_len; t ++)
+                        {
+                            rt_kprintf("%02x ", lan->send_buf[t]);
+                        }
+                        rt_kprintf("\r\n");
+                    }
+#endif
+                    rc = lwip_sendto(lan->udp_server, lan->send_buf, lan->send_len, 0,
+                                        (struct sockaddr *)&client_addr, (socklen_t)sizeof(client_addr));
+                    if(rc <= 0)
+                    {
+                        gagent_err("udp socket sendto failed! errno:%d\n", errno);
+                        break;
+                    }
+                    gagent_dbg("udp socket sendto len:%d\n", rc);
+                }
+            }
+            
+            if(FD_ISSET(lan->tcp_server, &readfds))
+            {
+                //tcp socket can read
+                addr_len= sizeof(struct sockaddr);
+                client_sock = lwip_accept(lan->tcp_server, (struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
+                if(client_sock < 0)
+                {
+                    gagent_err("tcp socket accept failed! errno:%d\n", errno);
+                    break;
+                }
+                gagent_dbg("client_sock:%d\n", client_sock);
+
+                for(id = 0; id < MAX_CLIENT; id ++) {
+                    if(lan->client_fd[id] == -1)
+                        break;
+                }
+                
+                if(id >= MAX_CLIENT)
+                {
+                    gagent_dbg("max client!\n");
+                    lwip_close(client_sock);
+                    continue;
+                }
+
+                lan->client_fd[id] = client_sock;
+                tcp_client_count ++;
+                gagent_dbg("new client: %d %s port:%d\n", id, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
+            }
+
+            for(id = 0; id < MAX_CLIENT; id ++)
+            {
+                if(lan->client_fd[id] == -1)
+                    continue;
+                    
+                if(FD_ISSET(lan->client_fd[id], &readfds))
+                {
+                    memset(lan->recv_buf, 0, sizeof(lan->recv_buf));
+                    lan->recv_len = lwip_recv(lan->client_fd[id], lan->recv_buf, sizeof(lan->recv_buf), 0);
+                    if(lan->recv_len <= 0)
+                    {
+                        gagent_err("lan:%d lan->recv_len:%d errno:%d\n", id, lan->recv_len, errno);
+                        
+                        lwip_close(lan->client_fd[id]);
+                        lan->client_fd[id] = -1;
+                        if(tcp_client_count > 0)
+                            tcp_client_count --;
+                        continue;
+                    }
+
+#ifdef LAN_RECV_DEBUG
+                    {
+                        int t;
+                        gagent_dbg("lan %d recv len:%d\n", id, lan->recv_len);
+                        for(t = 0; t < lan->recv_len; t ++)
+                        {
+                            rt_kprintf("%02x ", lan->recv_buf[t]);
+                        }
+                        rt_kprintf("\r\n");
+                    }
+#endif
+                    rc = lan_tcp_do_packet(lan);
+                    //
+                    if(rc == RT_EOK && lan->send_len > 0)
+                    {
+#ifdef LAN_RECV_DEBUG
+                        gagent_dbg("tcp client:%d send_len:%d\n", id, lan->send_len);
+                        {
+                            int t;
+                            for(t = 0; t < lan->send_len; t ++)
+                            {
+                                rt_kprintf("%02x ", lan->send_buf[t]);
+                            }
+                            rt_kprintf("\r\n");
+                        }
+#endif
+                        lan->send_len = lwip_send(lan->client_fd[id], lan->send_buf, lan->send_len, 0);
+                        if(lan->send_len <= 0)
+                        {
+                            gagent_err("tcp client [%d] send failed! errno:%d\n", id, errno);
+                            
+                            lwip_close(lan->client_fd[id]);
+                            lan->client_fd[id] = -1;
+                            if(tcp_client_count > 0)
+                                tcp_client_count --;
+                            continue;
+                        }
+                    }
+                }
+            }
+        }//end while
+
+        for(id = 0; id < MAX_CLIENT; id ++)
+        {
+            if(lan->client_fd[id] != -1)
+            {
+                lwip_close(lan->client_fd[id]);
+                lan->client_fd[id] = -1;
+            }
+        }
+        
+        tcp_client_count = 0;
+        gagent_close_tcp_socket(lan);
+        gagent_close_udp_socket(lan);
+        gagent_close_localudp_socket(lan);
+        
+    }
+}
+
+static int lan_local_send(lan_st *lan, void *data, int len)
+{
+    struct sockaddr_in server_addr = {0};
+    int send_len;
+    
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_port = lan->local_port;
+    server_addr.sin_addr = *((const struct in_addr *)&netif_default->ip_addr);
+    memset(&server_addr.sin_zero, 0, sizeof(server_addr.sin_zero));
+
+    send_len = lwip_sendto(lan->local_sock, data, len, MSG_DONTWAIT,
+                            (struct sockaddr *)&server_addr, sizeof(server_addr));
+    return send_len;
+}
+
+int gagent_lan_send_packet(lan_st *lan, rt_uint8_t action, rt_uint8_t *buf, rt_uint16_t buf_len)
+{
+    int rc = RT_EOK;
+    
+    memset(lan->send_buf, 0, sizeof(lan->send_buf));
+    lan->send_len = 0;
+
+    lan->send_len = gagent_set_one_packet(lan->send_buf, action, buf, buf_len);
+    
+#ifdef LAN_SEND_DEBUG
+	{
+        uint32_t i;
+        rt_kprintf("lan send_len:%d\n", lan->send_len);
+        for(i = 0; i < lan->send_len; i ++)
+        {
+            rt_kprintf("%02x ", lan->send_buf[i]);
+        }
+        rt_kprintf("\r\n");
+	}
+#endif
+
+    rc = lan_local_send(lan, lan->send_buf, lan->send_len);
+    if (rc == lan->send_len)
+    {
+        rc = RT_EOK;
+    }
+    else
+    {
+        rc = -RT_ERROR;
+    }
+    
+    return rc;
+}
+
+int gagent_lan_init(lan_st *lan)
+{   
+    lan_thread = rt_thread_create("gagent_lan", 
+                                    gagent_lan_thread, 
+                                    lan, 
+                                    4096, 
+                                    15, 
+                                    20);
+    if(lan_thread)
+        rt_thread_startup(lan_thread);
+    else
+    {
+        gagent_err("gagent_lan thread startup failed!\n");
+        rt_free(lan);
+        return -RT_ERROR;
+    }
+        
+    return RT_EOK;
+}

+ 265 - 0
gagent_mqtt.c

@@ -0,0 +1,265 @@
+/*
+ * File      : gagent_mqtt.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include "gagent_def.h"
+#include "gagent_cloud.h"
+
+
+static MQTTClient gagent_mqtt;
+
+#if (PKG_GAGENT_CLOUD_DEBUG == 1)
+#define MQTT_RECV_DEBUG
+#define MQTT_SEND_DEBUG
+#endif
+
+static int mqtt_push_ota(cloud_st *cloud, char *packet)
+{
+    return RT_EOK;
+}
+
+static int mqtt_trans_data(cloud_st *cloud, char *packet)
+{
+    uint16_t len, cmd;
+    char *index, *kv;
+    uint16_t kv_len;
+    uint8_t length_len, action;
+
+    action = 0;
+    kv = 0;
+    kv_len = 0;
+    
+    index = packet;
+    len = gagent_parse_rem_len((const uint8_t *)index + 4);
+    length_len = gagent_num_rem_len_bytes((const uint8_t *)index + 4);
+
+    index += (HEAD_LEN + length_len);
+
+    rt_memcpy(&cmd, index, 2);
+    index += 2;
+    
+    cmd = ntohs(cmd);
+    gagent_dbg("cmd:%x\n", cmd);
+
+    if(cmd == 0x90)
+    {
+        action = *index ++;
+        kv = index;
+        kv_len = len - 4;
+        cloud->sn = -1;
+    }
+    else if(cmd == 0x93)
+    {
+        memcpy(&cloud->sn, index, 4);
+        index += 4;
+        gagent_dbg("mqtt_sn:%d\n", cloud->sn);
+        //
+        action = *index ++;
+        kv = index;
+        kv_len = len - 8;
+    }
+    else
+        return -RT_ERROR;
+    
+    return gagent_cloud_recv_packet(CMD_FROM_MQTT, action, (rt_uint8_t *)kv, kv_len);
+}
+
+static void gagent_mqtt_callback(MQTTClient *c, MessageData *msg_data)
+{
+    extern cloud_st *cloud;
+    char *one_packet;
+    rt_uint32_t data_len;
+    rt_uint32_t total_len;
+    rt_uint16_t cmd;
+    rt_uint8_t len_num;
+    int rc = RT_EOK;
+
+#ifdef MQTT_RECV_DEBUG
+	{
+    size_t len;
+    char *data = (char *)msg_data->message->payload;
+    gagent_dbg("mqtt_callback topic_name: %d %s\n", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data);
+
+    rt_kprintf("mqtt recv_len:%d\n", msg_data->message->payloadlen);
+    for(len = 0; len < msg_data->message->payloadlen; len ++)
+    {
+        rt_kprintf("%02x ", data[len]);
+    }
+    rt_kprintf("\r\n");
+	}
+#endif
+
+    one_packet = (char *)msg_data->message->payload;
+    total_len = msg_data->message->payloadlen;
+    while(gagent_get_one_packet(one_packet, (int *)&data_len, &len_num, total_len) == RT_EOK)
+    {
+        memcpy(&cmd, one_packet + 6, 2);
+        cmd = ntohs(cmd);
+        
+        gagent_dbg("mqtt_cmd:%x\n", cmd);
+        switch(cmd)
+        {
+            case 0x10:                     //log on/off
+            break;
+            
+            case 0x90:                     //trans data
+            case 0x93:
+                rc = mqtt_trans_data(cloud, one_packet);
+            break;
+
+            case 0x210:                 //app number change
+
+            break;
+
+            case 0x211:                 //push ota
+                rc = mqtt_push_ota(cloud, one_packet);
+            break;
+
+            default:
+            break;
+        }
+        one_packet += (data_len + len_num + HEAD_LEN);
+        total_len -= (data_len + len_num + HEAD_LEN);
+
+        if(rc < RT_EOK)
+            break;
+    }
+}
+
+
+static void gagent_mqtt_connect_callback(MQTTClient *c)
+{
+    gagent_dbg("%s\n", __FUNCTION__);
+}
+
+static void gagent_mqtt_online_callback(MQTTClient *c)
+{
+    gagent_dbg("%s\n", __FUNCTION__);
+
+}
+
+static void gagent_mqtt_offline_callback(MQTTClient *c)
+{
+    gagent_dbg("%s\n", __FUNCTION__);
+
+}
+
+static int gagent_mqtt_client_publish(const char *topic, const char *msg, size_t msg_len)
+{
+    int rc = RT_EOK;
+    MQTTMessage message;
+
+    message.qos = QOS0;
+    message.retained = 0;
+    message.payload = (void *)msg;
+    message.payloadlen = msg_len;
+
+    rc = MQTTPublish(&gagent_mqtt, topic, &message);
+
+    return rc;
+}
+
+int gagent_mqtt_send_packet(cloud_st *cloud, rt_uint8_t action, rt_uint8_t *buf, rt_uint16_t buf_len)
+{
+    int rc = RT_EOK;
+    char topic[128];
+    
+    memset(topic, 0, sizeof(topic));
+    rt_snprintf(topic, sizeof(topic), "dev2app/%s", cloud->con->did);
+    gagent_dbg("pub_topic:%s\n", topic);
+
+    memset(cloud->send_buf, 0, sizeof(cloud->send_buf));
+    cloud->send_len = 0;
+
+    cloud->send_len = gagent_set_one_packet(cloud->send_buf, action, buf, buf_len);
+
+#ifdef MQTT_SEND_DEBUG
+	{
+    uint32_t i;
+    rt_kprintf("mqtt send_len:%d\n", cloud->send_len);
+    for(i = 0; i < cloud->send_len; i ++)
+    {
+        rt_kprintf("%02x ", cloud->send_buf[i]);
+    }
+    rt_kprintf("\r\n");
+	}
+#endif
+
+    rc = gagent_mqtt_client_publish(topic, cloud->send_buf, cloud->send_len);
+    return rc;
+}
+
+int gagent_mqtt_init(cloud_st *cloud)
+{
+    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+ 
+		RT_ASSERT(cloud != RT_NULL);
+
+    memset(&gagent_mqtt, 0, sizeof(gagent_mqtt));
+    
+    gagent_mqtt.host = cloud->mqtt_server;
+    gagent_mqtt.port = cloud->mqtt_port;
+
+    
+    memcpy(&gagent_mqtt.condata, &data, sizeof(MQTTPacket_connectData));
+    gagent_mqtt.condata.keepAliveInterval = 30;
+    gagent_mqtt.condata.MQTTVersion = 3;
+    gagent_mqtt.condata.cleansession = 1;
+    gagent_mqtt.condata.clientID.cstring = cloud->con->did;
+    gagent_mqtt.condata.username.cstring = cloud->con->did;
+    gagent_mqtt.condata.password.cstring = cloud->con->passcode;
+    
+    gagent_mqtt.buf_size = gagent_mqtt.readbuf_size = 1024;
+    gagent_mqtt.buf = malloc(gagent_mqtt.buf_size);
+    gagent_mqtt.readbuf = malloc(gagent_mqtt.readbuf_size);
+    if(!(gagent_mqtt.readbuf && gagent_mqtt.readbuf))
+    {
+        gagent_err("mqtt malloc failed!\n");
+        return -RT_ENOMEM;
+    }
+
+    gagent_mqtt.connect_callback = gagent_mqtt_connect_callback;
+    gagent_mqtt.online_callback = gagent_mqtt_online_callback;
+    gagent_mqtt.offline_callback = gagent_mqtt_offline_callback;
+
+    memset(cloud->sub_topic[0], 0, sizeof(cloud->sub_topic[0]));
+    snprintf(cloud->sub_topic[0], 128, "ser2cli_res/%s", cloud->con->did);
+    gagent_mqtt.messageHandlers[0].topicFilter = cloud->sub_topic[0];
+    gagent_mqtt.messageHandlers[0].callback = gagent_mqtt_callback;
+
+    memset(cloud->sub_topic[1], 0,sizeof(cloud->sub_topic[1]));
+    snprintf(cloud->sub_topic[1], 128, "app2dev/%s/#", cloud->con->did);
+    gagent_mqtt.messageHandlers[1].topicFilter = cloud->sub_topic[1];
+    gagent_mqtt.messageHandlers[1].callback = gagent_mqtt_callback;
+
+    gagent_mqtt.defaultMessageHandler = gagent_mqtt_callback;
+    
+    gagent_dbg("host:%s port:%d\n", gagent_mqtt.host, gagent_mqtt.port);
+    gagent_dbg("clientID:%s username:%s password:%s\n", 
+                    gagent_mqtt.condata.clientID.cstring, 
+                    gagent_mqtt.condata.username.cstring,
+                    gagent_mqtt.condata.password.cstring);
+    gagent_dbg("topic:%s\n", gagent_mqtt.messageHandlers[0].topicFilter);
+		
+    return paho_mqtt_start(&gagent_mqtt);
+}
+

+ 193 - 0
gagent_tool.c

@@ -0,0 +1,193 @@
+/*
+ * File      : gagent_tool.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-01-03     flyingcys    first version
+ */
+#include "gagent_def.h"
+
+int gagent_add_pkcs(char *src, int len)
+{    
+    char pkcs[16];
+    int i, cs = 16 - len % 16;    
+    
+    rt_memset(pkcs, 0, sizeof(pkcs));   
+    
+    for(i = 0; i < cs; i ++ )
+    {        
+        pkcs[i] = cs;    
+    }
+    
+    rt_memcpy(src + len, pkcs, cs);    
+    return (len + cs);
+}
+
+
+
+uint16_t gagent_parse_rem_len(const uint8_t* buf)
+{
+	uint16_t multiplier = 1;
+	uint16_t value = 0;
+	uint8_t digit;
+		
+	do
+	{
+		digit = *buf;
+		value += (digit & 0x7F) * multiplier;
+		multiplier *= 0x80;
+		buf++;
+	} while((digit & 0x80) != 0);
+
+	return value;
+}
+
+uint8_t gagent_num_rem_len_bytes(const uint8_t* buf)
+{
+	uint8_t num_bytes = 1;
+		
+	if ((buf[0] & 0x80) == 0x80)
+	{
+		num_bytes++;
+		if ((buf[1] & 0x80) == 0x80)
+		{
+			num_bytes ++;
+			if ((buf[2] & 0x80) == 0x80)
+			{
+				num_bytes ++;
+			}
+		}
+	}
+	return num_bytes;
+}
+
+uint8_t gagent_get_rem_len(int length, char *buf)
+{
+    uint8_t cnt = 0, digit;
+
+    do
+    {
+        digit = length % 128;
+        length /= 128;
+        
+    	if (length > 0) 
+        	digit = digit | 0x80;
+
+        buf[cnt] = digit;
+        cnt ++;
+    } while(length > 0);
+
+	return cnt;
+}
+
+int gagent_get_one_packet(char *packet, int *data_len, rt_uint8_t *len_num, int remain_len)
+{
+	char			*index;
+	uint16_t		len;
+	uint8_t			length_len;
+	
+	if(packet == NULL || data_len == NULL || len_num == NULL || remain_len <= 0) 
+	    return -1;
+
+	index = packet;
+
+	len = gagent_parse_rem_len((const uint8_t *)index + 4);
+	length_len = gagent_num_rem_len_bytes((const uint8_t*)index + 4);
+
+	*data_len = len;
+	*len_num = length_len;
+	
+	return RT_EOK;
+}
+
+int gagent_set_one_packet(char *packet, uint8_t action, uint8_t *buf, uint32_t buf_len)
+{
+    char length_bytes[4];
+    rt_uint32_t packet_len;
+    rt_uint8_t length_num, i;
+    char *index = packet;
+    
+    //head
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x00;
+    *index ++ = 0x03;
+
+    //
+    packet_len = buf_len + 3;           //flag + cmd * 2
+    if(buf && (buf_len > 0))
+    {
+        packet_len += 1;                //action
+    }
+
+    memset(length_bytes, 0, sizeof(length_bytes));
+    length_num = gagent_get_rem_len(packet_len, length_bytes);
+    for(i = 0; i < length_num; i ++)
+    {
+        *index ++ = length_bytes[i];
+    }
+
+    //flag
+    *index ++ = 0x00;
+
+    //
+    *index ++ = 0x00;
+    *index ++ = 0x91;
+
+    *index ++ = action;
+        
+    if(buf && buf_len > 0)
+    {
+        memcpy(index, buf, buf_len);
+        index += buf_len;
+    }
+
+    return (index - packet);
+}
+
+int gagent_strtohex(char *dst, char *src, int len)
+{
+    char h1,h2;
+    int i;
+
+    for (i = 0; i< len; i += 2)
+    {   
+        h1 = src[i];
+        if((h1 >= 'A') && (h1 <= 'F'))
+            h1 = h1 - 'A' + 10;
+        else if((h1 >= 'a') && (h1 <= 'f'))
+            h1 = h1 - 'a' + 10;
+        else
+            h1 = h1 - '0';
+        
+        h2 = src[i + 1];
+        if((h2 >= 'A') && (h2 <= 'F'))
+            h2 = h2 - 'A' + 10;
+        else if((h2 >= 'a') && (h2 <= 'f'))
+            h2 = h2 - 'a' + 10;
+        else
+            h2 = h2 - '0';
+
+        dst[i / 2] = ((h1 << 4) & 0xf0) + (h2 & 0x0f);
+    }
+		
+		return len / 2;
+}
+
+