最新消息:QQ物联、百度物联网、阿里物联平台、华为物联网、机智云、中国移动物联网开放平台设备云OneNET 等都是我们未来生活中不可缺少的远程平台。我们将在Q物联这里学习使用、利用这些工具技术,甚至开发和创造。

中国移动物联网开放平台OneNet接入使用教程(11):如何利用Stm32开发板和EDP协议实例连接OneNet平台代码(2)

中国移动设备云OneNet Q物联 1516浏览 0评论



数据(透传)转发(EDP协议)

该实例代码是在“数据上传(EDP协议)”小节所讲述的实例代码上稍加修改得到,首先我们要在OneNet上有两个已经注册好的设备,设备ID 和APIKey 分别为:

1
2
"131988" "sUwBsToABOTYWAY6VBKMztwyIzwA"
"131658" "mgDiVsQ7E8bPUwfBDtTy4K8yMtMA"

我们有两台开发板设备,其中设备1 使用ID“131988”,并周期性向设备2 发送字符串“Hi, Im 131988”;设备2 使用ID“131658”,并周期性向设备1 发送字符串“Hi, Im 131658”。直接编译代码并下载到设备1 中;另一方面,对于设备2,需要注释掉代码中的DEVICE1 宏定义,然后编译代码并下载到设备2 中。本例程中的代码支持DHCP 功能,因此不必为每个设备重新配置IP 地址,但是需要路由器开启DHCP 功能。如果读者使用自己定义的设备号和APIKey,则只需把下面的相关宏定义内容改为自己的设备ID 和APIKey。如下图所示:

数据(透传)转发协议.png

另外,要实现数据转发,在“数据上传(EDP协议)”小节实例中,main、App_TaskStart两个函数保持不变,主要修改的函数为edp_demo函数,如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void edp_demo(void * arg)
{
    int sockfd, ret;
    EdpPacket* send_pkg;
 
    /*初始化内存*/
    uMEM_Init();
    /*自动获取IP地址*/
    while(enc28j60_netif.dhcp->state != DHCP_BOUND)
        OSTimeDly(10);               
 
    sys_timer = sys_now();
 
    /* 与服务建立socket连接 */
    sockfd = Open(SERVER_ADDR, SERVER_PORT);
    if(sockfd < 0)
    {
        return;
    }
 
    /*产生并发送EDP设备连接请求*/
    send_pkg = PacketConnect1(DEV_ID, API_KEY);
    ret = DoSend(sockfd, send_pkg->_data, send_pkg->_write_pos);
    DeleteBuffer(&send_pkg);
 
    while(1)
      {  
         /*数据接收和发送函数*/
        client_process_func((void*)&sockfd);
 
        /*发生错误,关闭socket连接*/
        Close(sockfd);
       }
}

和“数据上传(EDP协议)”小节中的edp_demo函数最大的不同在于,该函数在while循环中调用了client_process_func函数,来看看client_process_func函数的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int client_process_func(void* arg)
{
    int sockfd = *(int*)arg;
    fd_set readset;
    fd_set writeset;
    int i, maxfdp1;
 
    for(;;)
    {
        maxfdp1 = sockfd+1;
 
        /*套节字集合清空 */
        FD_ZERO(&readset);
        FD_ZERO(&writeset);
 
        /*加入读写套接字集合*/
        FD_SET(sockfd, &readset);
        FD_SET(sockfd, &writeset);
 
        /*检测套接字是否可读可写*/
        i = select(maxfdp1, &readset, &writeset, 0, 0);
 
        /*套接字不可读不可写*/
        if(i == 0)
            continue;
 
        /*检测sockfd是否在读套接字集合里面*/
        if(FD_ISSET(sockfd, &readset))
        {
            /*如果可读,接收网络数据*/
            if(recv_func(sockfd) < 0)
                break;
        }
        /*如果socket 准备好可写,调用send_data_to_remote函数发送数据到远程终端*/
        if(FD_ISSET(sockfd, &writeset))
        {
            if(send_data_to_remote(sockfd) < 0)
                break;
        }
    }
    return -1;
}

该函数对socket进行一系列设置,主要目的就是实现数据实时的接收和发送,接收使用recv_func函数,发送使用send_data_to_remote函数,下面来看这两个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int send_data_to_remote(int arg)
{
    unsigned int now = sys_now();
    int sockfd = arg;
    int ret = 0;
    EdpPacket* send_pkg;
 
    /*每10s发送一次数据*/
    if(now - sys_timer < 5000)
    {
        return 0;
    }
    sys_timer = now;
 
    /*封装EDP 数据包,包类型为转发(透传)数据包*/
    send_pkg = PacketPushdata(REMOTE_ID, GREETING, sizeof(GREETING));
    if(send_pkg == NULL)
    {
        Printf("PacketPushdata error\n");
        return -1;
    }
 
    /*发送EDP 数据包*/
    ret = DoSend(sockfd, send_pkg->_data, send_pkg->_write_pos);
    DeleteBuffer(&send_pkg);
 
    return ret;
}

该函数主要实现将用户数据(Hi, Im xxxxxx)打包并通过发送到远端主机,数据打包调用库函数PacketPushdata实现,该函数由平台EDP协议相关的SDK(edp_c)提供,该SDK下载地址为:https://github.com/cm-heclouds/edp_c,与之相类似的函数还有:

1
2
3
4
/* 实现JSON串数据存储和转发*/
EdpPacket* PacketSavedataJson(const char* dst_devid, cJSON* json_obj);
/*实现二进制数据存储和转发*/
EdpPacket* PacketSavedataBin(const char* dst_devid, cJSON* desc_obj, uint8* bin_data, uint32 bin_len);

recv_func函数的功能是从网络接收数据包,并解析出数据包里面携带的用户数据:

7
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
int recv_func(int arg)
{
    int sockfd = arg;
    int error = 0;
    int n, rtn;
    uint8 mtype, jsonorbin;
 
    RecvBuffer* recv_buf = NewBuffer();
    EdpPacket* pkg;
 
    char* src_devid;
    char* push_data;
    uint32 push_datalen;
 
    cJSON* save_json;
    char* save_json_str;
 
    cJSON* desc_json;
    char* desc_json_str;
    char* save_bin;
    uint32 save_binlen;
    int ret = 0;
    do
    {
        /*接收网络数据*/
        n = Recv(sockfd, buffer, 512, 0);
        if(n <= 0)
        {
            Printf("recv error, bytes: %d\n", n);
            error = -1;
            break;
        }
        Printf("recv from server, bytes: %d\n", n);
        WriteBytes(recv_buf, buffer, n);
        while(1)
        {
            if((pkg = GetEdpPacket(recv_buf)) == 0)
            {
                Printf("need more bytes...\n");
                break;
            }
            /*解析EDP数据包的类型*/
            mtype = EdpPacketType(pkg);
            switch(mtype)
            {
                /*连接响应数据包解析*/
                case CONNRESP:
                    rtn = UnpackConnectResp(pkg);
                    /*串口打印解析结果*/
                    Printf("recv connect resp, rtn: %d\n", rtn);
                    break;
                /*存储(&转发)数据包解析*/
                case PUSHDATA:
                    UnpackPushdata(pkg, &src_devid, &push_data, &push_datalen);
                    /*串口打印解析结果*/
                    Printf("recv push data, src_devid: %s, push_data: %s, len: %d\n",
                           src_devid, push_data, push_datalen);
                    uMEM_Free(src_devid);
                    uMEM_Free(push_data);
                    break;
                /*转发(透传)数据包解析*/
                case SAVEDATA:
                    if(UnpackSavedata(pkg, &src_devid, &jsonorbin) == 0)
                    {
                        if(jsonorbin == 0x01)
                        {
                            /* json */
                            ret = UnpackSavedataJson(pkg, &save_json);
                            save_json_str=cJSON_Print(save_json);
                            /*串口打印解析结果*/
                            Printf("recv save data json, ret = %d, src_devid: %s, json: %s\n",
                                   ret, src_devid, save_json_str);
                            uMEM_Free(save_json_str);
                            cJSON_Delete(save_json);
                        }
                        else if(jsonorbin == 0x02)
                        {
                            /* bin */
                            UnpackSavedataBin(pkg, &desc_json, (uint8**)&save_bin, &save_binlen);
                            desc_json_str=cJSON_Print(desc_json);
                            /*串口打印解析结果*/
                            Printf("recv save data bin, src_devid: %s, desc json: %s, bin: %s, binlen: %d\n",
                                   src_devid, desc_json_str, save_bin, save_binlen);
                            uMEM_Free(desc_json_str);
                            cJSON_Delete(desc_json);
                            uMEM_Free(save_bin);
                        }
                        uMEM_Free(src_devid);
                    }
                    break;
                /*心跳响应数据包解析*/
                case PINGRESP:
                    UnpackPingResp(pkg);
                    Printf("recv ping resp\n");
                    break;
                default:
                    Printf("recv failed...\n");
                    break;
            }
            DeleteBuffer(&pkg);
        }
    }
    while(0);
    DeleteBuffer(&recv_buf);
    return error;
}

以上就是要修改的全部代码,代码修改完成后,编译并下载到两块开发板设备,注意编译设备2代码时需要注释掉宏定义#define DEVICE1,然后将设备连接网线,在串口调试工具中设备2打印的调试信息如下:

数据(透传)转发协议-2.png

设备2(设备ID 131658)接收到设备1(设备ID 131988)发送过来的信息“Hi, Im 131988”,设备1(设备ID 131988)接收到设备2(设备ID 131658)发送过来的信息“Hi, Im 131658”,如下图:

数据(透传)转发协议-3.png

转载请注明:Q物联网 » 中国移动物联网开放平台OneNet接入使用教程(11):如何利用Stm32开发板和EDP协议实例连接OneNet平台代码(2)

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址