查看: 5649|回复: 3

[8月赛] [麒麟传说]http向onenet平台传输数据代码分析

[复制链接]

1

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2017-8-1 17:15:49 | 显示全部楼层 |阅读模式
本帖最后由 zhuzhiqing 于 2017-8-4 10:42 编辑

我是今年中移物联网的实习生,之前只是简单的学过一些单片机使用与控制,但是现在也忘得七七八八了,来这里实习之前我只是听说过物联网这个名词,并此没有多大的认知,经过一段时间的学习与培训,也渐渐明白了物联网的概念,同时惊讶于物联网设备能给我们生活提供的诸多便利,相信物联网这个词会越来越走进大众生活,成为人们生活中不可或缺的一部分。
   由于我并不太会硬件,我是以一个初学的物联网开发者的角度去写这篇帖子,帖子的源码来自中移物联网的杨周正和刘杨给我们培训时的例程;在两位大哥的教导下,由于自己是小白,踩了无数的坑,也闹了很多笑话,但最终还是傻瓜式地完成了通过网络去控制设备等学习任务。对于一个初学者来说,这过程中的新奇与欣喜,自然也是不言而喻的。
———————————————————我是分割线———————————————
废话不多说下面开始正文,这里给大家分享一下该源程序的逻辑和流程,限于本人不太懂硬件,并不涉及到过于底层的代码,只是分享一下自己的理解,希望能让和我一样的小白明白写物联网程序时应该实现什么模块,心里有个大致的流程即可。 1.png
首先看c语言中的入口函数main,只有短短的几行,每行的代码已经做了注释,我们可以看到首先初始化了硬件,uc/os-II操作系统,和一个app_init(),然后创建了几个任务,最后
开始让操作系统开始调度任务执行就好。
怎么样是不是感觉流程很简单,是的。对初学者而言,只需要依葫芦画瓢,先初始化几个部分,然后添加想让物联网设备执行的任务,最后开始执行即可。 我们接下来看看app_innit()做了什么
2.png
可以看到这一部分和之前的OSInit()一样,调用了一个app_init_comm(),然后调用了USATR_SendStr()发送了一些字符串,接下来如果存在led和oled设备的话还会在显示屏上显示相关的信息(这里是onenet_dev_id[dev_id][0]即该设备在onenet平台上对应的设备id号),再点跳转看看app_init_comn():
3.png
这下就比较明了了,在这个函数里面,分别初始化了LED,IIC,ADXL345,RTC   等模块,分别对应着板子上的,二极管,IIC通信,加数重力传感器,实时时钟等模块,还有刚刚我们看到的USATR模块,这些init函数点进去看了就是比较贴近底层物理模块的函数,我也不太明白其中细节就不贴出来了,到了这里我们应该要明白,在真正地让我们设备运行起来时候之前,一定要记得将我们用到的物理模块进行初始化,对于我们新添加进去的模块(比如传感器等等)也应该参考该模块的说明书,写好该模块的驱动,初始化函数等。
   -----------------------------------------------------------------------------------------------

假设已经弄好以上的准备工作就可以 写我们真正的任务程序了,在任务代码中我们需要利用这些驱动程序去操控硬件去做工作,对于这个例子而言我们目标是用这个开发板将传感器接受的到的数据通过http协议上传到onenet平台,我们接下来看一看这个Task_APP到底是怎么做的。
4.png
这个就是任务程序,OS开头的都是us/os-ii操作系统提供的功能,大致作用已经注释在后面。可以看到主要有一个Appdataupdate(),HTTP_LoadDatastream(),MOD_SendData(),三个函数,从名字大致能猜出来,它们分别对应着获取数据,封装成http协议格式数据,发送数据,是的,它们就是这么做的我们接来下具体看看 究竟是怎么做的
5.png
这个便是获取所有数据的代码,Mod_TypeRd()返回的是wifi模块的相关信息,其它的功能已经写在注释里面, SHT2x是一个温湿度传感器模块,因为之前已经写好了该模块的驱动,在这里只需要让它去更新传感数数据即可。这里以SHT2x_valueupTemp()为例贴一下具体获取数据代码;
6.png
7.png

可以看到该模块和板子芯片之间是以IIC方式(IIC具体通信协议可以自己找资料查阅)传输数据的,任务程序向 传感器模块发出更新数据指令后,之后尝试50次去向传感器拿数据,拿到成功后保存到calu_temp即可,一般来讲传输和接受数据的格式需要具体查阅传感器对应的手册。

获取到所有要发送的数据之后,之后就要通过http协议去向onenet平台发送数据,(http协议格式也可查阅资料了解)HTTP_LoadDatastream(),就是将所有数据封装成http报文格式。 8.png
9.png
可以看到首先在缓冲区写入了 http报文的头部(注意头部和正文之间有两个\r\n),然后在
DSTREAM_GetDataStream_Body()中封装了剩下的正文部分,注意这里的http要求的正文体长度是未填的,在填好了正文体后,根据正文体的长度去更正的。

再进入DSTREAM_GetDataStream_Body()这个封装正文体函数之前,先看一下DSTREAM这个类型的格式:
10.png
其中 name是你要上传数据的名称,,data是你要发送的真实数据,dataType是表明你的数据是什么类型(int?float?string?)方便封装函数封装,flag标志正文体函数时候将这一条数据封装进正文体。明白了这个结构的定义,我们在看看正文体封装函数DSTREAM_GetDataStream_Body();








回复

举报

1

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
 楼主| 发表于 2017-8-1 17:42:05 | 显示全部楼层
zhuzhiqing 发表于 2017-8-1 17:41
忘记贴附件了  这里是源码文件。。

微信配网框架工程.rar (8.68 MB, 下载次数: 474)

1

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
 楼主| 发表于 2017-8-1 17:41:04 | 显示全部楼层
忘记贴附件了  这里是源码文件。。

1

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
 楼主| 发表于 2017-8-1 17:33:15 | 显示全部楼层
本帖最后由 zhuzhiqing 于 2017-8-3 09:55 编辑

11.png
12.png
这个函数 首先根据 你的type决定你要发送post正文段的格式,其他的格式的封装代码和图示大同小异 不再贴出来了。这里通过一个for循环不断往缓冲区中接字符串化的数据,字符串化的数据通过DSTREAM_tostring())得到,并保存在data_buf中。
13.png
可以看到 这个函数就是 简单的根据真实数据的类型去用snprintf()格式化字符串buf。
正文体封装函数 里面也有一小细节值得注意 ,已经注释中标出。
已经得到了封装好的http请求之后,就是调用MOD_SendData()具体的发送数据
14.png
这是定义好的 send_buf_arr_t结构:
15.png
这是预先定义好的一些数据:
16.png
在mod_senddata()中,首先检查是否索引send_index_wr对应的缓存结构是否可用,如果可用尝试分配512字节给ptr成员,然后将send_buf_arr_t 成员各项设置好,将sts 设置为不可用(因为自己要用这一块),如果带发送的数据正好保存在可以发送的缓存结构上(send_idex_wr ==  send_idex_sd) 就发送数据,然后两个索引加一 ,Mod_SendReq()发送成功后,会自动将刚发送的缓冲结构设置为可用状态。这里值的注意的是缓冲区数据结构设置为8  send_idex_wr++;send_idex_wr  &= BUF_MASK; 正好配合 完成0-7的不间断循环,用与操作避免了取余操作。可能有人觉得为什么要大费周章去弄一个缓存区呢,我个人觉得因为发送可能由于网络原因,发送较慢,如果只有一个缓冲区会导致后面的代发数据全部丢弃,用缓冲区可以一定程度改善这一情况。由于mod_sendReq()是封装在库里面的,我没有去检验是否在Mod_SendReq()发送成功后,会自动将刚发送的缓冲结构设置为可用状态。各位看官看到这里可以留个心眼,自行调试一下。
至此我们的任务函数也就至此分析完毕了。将这些整个工程烧录进开发板就可以在onenet平台源源不断地接到开发板接受到的数据。
以下是该例程 发往onenet平台的  DATA_STREAM 数据流。随后我会以,温度,Cmpletime为例子 利用onenet提供的数据展示功能 看看是否会源源不断地收到数据。

这是温度的例子,因为在室内可能 温差变化不大。。。。。。。。。
在本例程中 这是个cmpletime这个不是数据发送时间 而是一个编译时的时间 它是一个常数。
明白了开发逻辑流程我们可以试着往数据流添加一些自定义数据,检验一下逻辑正确与否;

首先在DATA_STREAM添加一项数据。
然后在AppDataUpdate()里面尝试不断更改Test_Data的值:
具体的Get_Test_Sensor()实现为:
这样每次 对数据进行Updata操作时,我们要发送的Test_Data 就会加一。接下来打开onenet 平台看看

果然有了MY_Test_Data这一项,并且值是从0开始递增的,但是可以看到中间有一段变化,
可能是因为 发送的数据 有可能发送失败或者有网络延迟的情况,单总体上看确实是从0开始慢慢增大的。
在 main中 还创建了  Task_Net  Task_Clock Task_Led 三个任务,它和Task_App是 并行由操作系统调度的,具体完成了什么功能可以看各个任务程序的代码。

好了,这篇帖子也要接近尾声了, 现在总结一下,对于我这样小白来说,如果套用示例代码的设计逻辑,想把数据上传到onenet平台,我们只需要需要做:
1, 查外接模块对应的用户手册结合开发板的开发手册,写好外部模块的init函数,驱动。
在任务程序调度之前初始化好改模块。
2, 写好要传输的数据的updata 函数(这个函数可能要控制外部模块),将这部分代码加在
AppDataUpdate(),
3, 在DATA_STREAM数组中添加自己要上传数据的DATA_STREAM结构体,指明名字,数据类型,起始地址等等。

4, 如果还想让开发板做其他的任务,只需要在OSTaskCreate()添加对应的任务程序即可。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
突然发现  那个示例用的是edp协议,好尴尬。。。。  但是应该只是http协议的封装变成了 edp协议的封装其他的大致流程还是这样。。。。
暂时就写这么多了。。。有一些偏底层的地方的分析,出错的地方会比较高(比如温湿度传感器,以及最后的mod_senddata(),毕竟 纯小白。。。)请大家指正,。。。



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表