当前位置:   article > 正文

基于GEC6818开发板的华为云物联网数据监控项目整理

gec6818开发板

一、项目架构

1、熟悉MQTT协议

在做项目之前,我们首先需要知道项目需要用到什么模块,什么协议,还有用哪个云端存储上传的数据。

在此分享我做项目时的要求:

 

根据要求我们可以知道,在设备端我们需要利用开发板上的ADC旋钮,LED灯和蜂鸣器,并且想办法把这些设备的状态上传到云端,那如何将设备的状态上传到云端呢?这就利用到了MQTT协议。

2、什么是MQTT协议?

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

上面的说法是一个概括,如果想要具体了解MQTT协议,可以根据下面链接了解:零基础入门学用物联网 – MQTT基础篇 – 目录 – 太极创客 (taichi-maker.com)

3、如何利用MQTT

在了解完什么是MQTT协议后,我们会冒出一个疑问,难道要我们自己写一个使用MQTT协议的代码与云端进行通信吗?那当然不是,很明显我们目前的能力还不够,所以我们就需要大厂的帮助。在此项目中,我选择使用华为云进行物联网连接实验,为了帮助设备快速连接到物联网平台,华为提供了IoT Device SDK。支持TCP/IP协议栈的设备集成IoT Device SDK后,可以直接与物联网平台通信。不支持TCP/IP协议栈的设备,例如蓝牙设备、ZigBee设备等需要利用网关将设备数据转发给物联网平台,此时网关需要事先集成IoT Device SDK。

在这里,我们的想法是,先登录华为云,创建一个云设备,再通过华为云提供的SDK做一定的修改,放在ubuntu上运行,先连通ubuntu和云端的通信。再想办法从开发板那获取到真实设备端的数据。或许有同学会问,那为啥不直接把华为云提供的SDK放到开发板上呢,毕竟开发板也可以连通网络。答案是可以的,但是开发板是基于ARM架构的,华为云提供的SDK还需要进行修改才能在开发板上部署,其中需要用到不同的库,笔者自己试着弄了一下,发现华为云上面提供的操作指导并不完整,或者资源连接到外网下载,没有梯子的话访问不了,而且在处理某一些用到的库的时候,又会报莫名其妙的错误,所以笔者是放弃了。大家有兴趣也可以自己尝试弄一下。在此我们就在ubuntu上部署SDK,让Ubuntu作为一个中间网关,接收开发板的真实设备数据,再转发上华为云。

4、如何利用华为云

首先,我们需要登录华为云,再搜索框搜索“设备接入”。

选择第一个,因为笔者已经创建好了设备,所以直接选择第一个。如果没有创建设备过的话,直接搜索“设备接入 IoTDA”,界面应该是这样的:

直接选免费试用

这个区域是有讲究的,你以后登录华为云的时候,要记得在哪个区域创建了设备,就像你玩游戏在哪个大区创建了角色一样。

实例名称可以随便填,但是最好填一个跟项目相关的名称。然后进来是这样子的:

因为当前的实例是基础版的,我们需要切换到刚刚创建的专业版实例,这里笔者的实例名称是“互联网实验”,点击详情,然后是这样子的:

点击切换实例,再点击总览:

进来后再点击向导式极速体验快速创建一个云端设备

进来后是这样的:

点击创建产品:

点击注册设备:

点击下一步:

点击下载设备演示包,就会下载一个华为云为你写好的SDK

到此,我们需要回头改一些我们匆匆创建好的设备信息,先修改一下设备的密码:

修改完后点确定

修改完密码后我们需要修改一下设备的属性,把它改成我们需要的属性:

命令可以像这样子设置,也可以发送不同的数据类型,笔者是发的bool型数据用于开关灯,如果命令有多种情况,就需要发送别的数据类型。

这个是笔者已经弄好的设备,可以作为对照

好了,到了这一步,我们在云端的工作就已经做好了。

5、打通SDK和华为云的通信,激活云端设备

既然我们已经在云端创建了一个设备,也就是一个云设备,并不是真实的设备,我们需要利用华为云给我们提供的SDK,并修改一下代码,然后放到Ubuntu运行,建立与云端的通信,才能激活我们刚刚在华为云创建的设备。首先,我们把文件放到vscode上:

文件总体是这样子的,这里我们主要对AgentLiteDemo.c还有ClientConf.json进行修改:

先改ClientConf.json:

按照自己的设备id,密码修改

把后面的端口号删除,还有那两个冒号,因为如果固定端口的话,可能出现连不上的情况。

网址跟这个一样:

设备ID在这:

然后再修改AgentLiteDemo.c:

  1. #include "stdio.h"
  2. #include "signal.h"
  3. #if defined(WIN32) || defined(WIN64)
  4. #include "windows.h"
  5. #endif
  6. #include "pthread.h"
  7. #include <math.h>
  8. #include "hw_type.h"
  9. #include "iota_init.h"
  10. #include "iota_cfg.h"
  11. #include <stdlib.h>
  12. #include <stdbool.h>
  13. #include <unistd.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <strings.h>
  17. #include <errno.h>
  18. #include <pthread.h>
  19. #include <semaphore.h>
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <arpa/inet.h>
  24. #include <net/if.h>
  25. #include "LogUtil.h"
  26. #include "JsonUtil.h"
  27. #include "StringUtil.h"
  28. #include "iota_login.h"
  29. #include "iota_datatrans.h"
  30. #include "string.h"
  31. #include "cJSON.h"
  32. #include "sys/types.h"
  33. #include "unistd.h"
  34. #include "iota_error_type.h"
  35. /* if you want to use syslog,you should do this:
  36. *
  37. * #include "syslog.h"
  38. * #define _SYS_LOG
  39. *
  40. * */
  41. char* workPath = ".";
  42. char* gatewayId = NULL;
  43. int alarmValue = 0;
  44. char* serverIp_ = "";
  45. int port_ = 1883;//原本是8883,需要把端口改成1883,不然与华为云的tcp会连接失败
  46. char* username_ = "64f82801a266cb7f6e6abfd1_gec6818";//deviceId,这个需要根据自己的情况做修改
  47. char* password_ = "12345678";//这也也需要根据自己的情况做修改
  48. int disconnected_ = 0;
  49. char *subDeviceId = "f6cd4bbb1a8ab53acbb595efd0e90199_ABC123456789";//这个一般不用改
  50. int sleepTime = 5000;
  51. void timeSleep(int ms)
  52. {
  53. #if defined(WIN32) || defined(WIN64)
  54. Sleep(ms);
  55. #else
  56. usleep(ms * 1000);
  57. #endif
  58. }

上面的代码中我已经加入了许多我需要用到的头文件,如果编译出现缺少头文件的情况,需要你加上对应的头文件。

  1. void Test_propertiesReport()
  2. {
  3. int serviceNum = 1;//此处是上报的服务个数
  4. ST_IOTA_SERVICE_DATA_INFO services[serviceNum];
  5. cJSON *root;
  6. root = cJSON_CreateObject();
  7. //设置一个p操作,如果没有资源会在此处阻塞等待
  8. sem_wait(&s);
  9. //需要根据自己的设备进行修改,中间的是你的云端设备属性,第三个是值,这里笔者已经用变量代替,原本的只是一个随机数,后面你需要用变量替换
  10. cJSON_AddNumberToObject(root, "led", LED_value);
  11. cJSON_AddNumberToObject(root, "adc", ADC_value);
  12. cJSON_AddNumberToObject(root, "pwm", BEEP_value);
  13. char *payload;
  14. payload = cJSON_Print(root);
  15. cJSON_Delete(root);
  16. services[0].event_time = getEventTimeStamp(); //if event_time is set to NULL, the time will be the iot-platform's time.
  17. services[0].service_id = "开发板数据监控系统";//这里是一开始弄的那个产品名称,需要根据自己的情况修改
  18. services[0].properties = payload;
  19. int messageId = IOTA_PropertiesReport(services, serviceNum);
  20. if(messageId != 0)
  21. {
  22. printfLog(EN_LOG_LEVEL_ERROR, "AgentLiteDemo: Test_batchPropertiesReport() failed, messageId %d\n", messageId);
  23. }
  24. free(payload);
  25. }
  1. void setConnectConfig(){
  2. FILE *file;
  3. long length;
  4. char *content;
  5. cJSON *json;
  6. file=fopen("./ClientConf.json","rb");
  7. fseek(file,0,SEEK_END);
  8. length = ftell(file);
  9. fseek(file,0,SEEK_SET);
  10. content = (char*)malloc(length+1);
  11. fread(content,1,length,file);
  12. fclose(file);
  13. json = cJSON_Parse(content);
  14. username_ = JSON_GetStringFromObject(json, "deviceId", NULL);
  15. password_ = JSON_GetStringFromObject(json, "secret", NULL);
  16. char *url = JSON_GetStringFromObject(json, "serverUri", NULL);
  17. deleteSubStr(url,"ssl://");
  18. deleteSubStr(url,":1883");//把这个地方的端口改成1883
  19. serverIp_ = url;
  20. }

 把上面的端口改一改

如果你需要弄云端下发命令,那么还需要修改一处:

这是原本的代码:

  1. void handleCommandRequest(void* context, int messageId, int code, char *message, char *requestId)
  2. {
  3. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), messageId %d, code %d, messsage %s, requestId %s\n", messageId, code, message, requestId);
  4. JSON * root = JSON_Parse(message); //Convert string to JSON
  5. char* object_device_id = JSON_GetStringFromObject(root, "object_device_id", "-1"); //get value of object_device_id
  6. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), object_device_id %s\n", object_device_id);
  7. char* service_id = JSON_GetStringFromObject(root, "service_id", "-1"); //get value of service_id
  8. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), content %s\n", service_id);
  9. char* command_name = JSON_GetStringFromObject(root, "command_name", "-1"); //get value of command_name
  10. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), name %s\n", command_name);
  11. JSON* paras = JSON_GetObjectFromObject(root, "paras"); //get value of data
  12. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), id %s\n", paras);
  13. if (paras)
  14. {
  15. sleepTime = JSON_GetIntFromObject(paras, "value", 1) * 1000;
  16. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), sleepTime %d\n", sleepTime);
  17. }
  18. Test_commandResponse(requestId); //command reponse
  19. JSON_Delete(root);
  20. }

这是笔者根据自己的项目需要进行的修改,仅供参考:

  1. void handleCommandRequest(void* context, int messageId, int code, char *message, char *requestId)
  2. {
  3. //printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: handleCommandRequest(), messageId %d, code %d, messsage %s, requestId %s\n", messageId, code, message, requestId);
  4. //这里的修改需要特别注意,如果需要对两种不同的命令做出判断,需要先提取command_name后,再细分判断,不然会报错
  5. JSON * root = JSON_Parse(message); //Convert string to JSON
  6. char* command_name = JSON_GetStringFromObject(root, "command_name", "-1");
  7. if(strstr(command_name,"led"))
  8. {
  9. JSON* paras = JSON_GetObjectFromObject(root, "paras");
  10. JSON* lled = JSON_GetObjectFromObject(paras, "led");
  11. // memcpy(sendled[0],cJSON_Print(lled),strlen(cJSON_Print(lled)));
  12. // printf("%s\n",sendled[0]);
  13. if (JSON_GetBoolFromObject(paras, "led状态", NULL) == true )
  14. {
  15. strcpy(ledstat, "true");
  16. //设置一个v操作,表示收到云端下发的命令
  17. sem_post(&xf);
  18. }else
  19. {
  20. strcpy(ledstat, "false");
  21. //设置一个v操作,表示收到云端下发的命令
  22. sem_post(&xf);
  23. }
  24. printf("%s\n", JSON_GetBoolFromObject(paras, "led状态", NULL)?"开灯":"关灯");
  25. }
  26. if(strstr(command_name,"beep"))
  27. {
  28. JSON* paras = JSON_GetObjectFromObject(root, "paras");
  29. JSON* lled = JSON_GetObjectFromObject(paras, "beep");
  30. if (JSON_GetBoolFromObject(paras, "beep状态", NULL) == true )
  31. {
  32. strcpy(beepstat, "true");
  33. //设置一个v操作,表示收到云端下发的命令
  34. sem_post(&bp);
  35. }else
  36. {
  37. strcpy(beepstat, "false");
  38. //设置一个v操作,表示收到云端下发的命令
  39. sem_post(&bp);
  40. }
  41. printf("%s\n", JSON_GetBoolFromObject(paras, "beep状态", NULL)?"开警报":"关警报");
  42. }
  43. JSON_Delete(root);
  44. }

如此修改完之后,保存后,在编译器直接输入make进行编译,然后给脚本文件start.sh赋予777权限,不然执行的时候会报权限不足的问题,编译好之后,在终端直接输入./start.sh执行这个SDK文件,运行结果会是如此:

可以看到,Ubuntu已经顺利执行华为云提供的SDK,在云端也可以看见设备已经激活,并且已经向云端发送ADC,LED,BEEP的数据,(此时的数据并不是真实设备的数据,只是rand函数随机模拟的数据,如果你想要发送真实设备的数据,还需要接通开发板上的设备),反正不管怎么说,现在已经打通了Ubuntu与云端的通信,下一步就应该想着怎么打通Ubuntu与开发板的联系,就是怎么把开发板的真实设备状态通过tcp或者udp发送到ubuntu,再由ubuntu转发给云端,以达到物联网数据监测的目的。

6、编写设备端代码

这里说的设备端是真实设备,也就是开发板上的蜂鸣器,LED和ADC旋钮,如果你需要将设备的状态简单的显示在开发板上,那还需要用到lcd屏幕,要控制这些硬件,当然需要相应的驱动模块,这里笔者就不给出驱动文件,在这提一嘴笔者踩过的雷,驱动一定要安装正确的版本与之相对应,不然会出现莫名其妙的错误。

这里给出一些常用的驱动命令:

lsmod:列出当前装载的驱动模块

rmmod: 删除指定的驱动模块

insmod: 安装指定驱动模块

还有对应的设备路径:

蜂鸣器:beep/buzzer/pwm

ADC: adc/gec6818_adc

LED: led/Led/gec_led

按键:button/gecBt/key

好了,铺垫了这么久,我们现在开始编写设备端的代码。在编写之前,我们需要考虑,每一个设备都有其对应的控制代码,还有其对应的逻辑控制。也就是每一个设备都有自己的.c文件,每个.c文件都有一个main函数。那么该如何实现,这些设备之间的交互呢,比如ADC到达一定的阈值后会触发警报。那就需要用到我们学过的知识了——进程间的通信。我们可以弄一个管理进程,通过exce函数启动其他设备的进程,例如:

  1. #include "head.h"
  2. //蜂鸣器标记位,配合共享内存使用的,可惜没玩明白共享内存,暂时报废
  3. const char *beepmanageron = "true";
  4. //设置一个互斥锁,所有的锁都是为了共享内存准备的,很可惜没玩明白共享内存
  5. pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  6. int main(int argc, char const *argv[])
  7. {
  8. //想用共享内存没有用出来,可惜,所以关于共享内存的代码都是无效的,不用管
  9. int shmid;
  10. // 创建或打开一个大小为30的SHM对象,用来存放开关的状态,获取其ID
  11. shmid = shmget(key, 40, IPC_CREAT|0666);
  12. if(shmid < 0)
  13. {
  14. perror("创建SHM对象失败");
  15. }
  16. //映射共享内存
  17. char *shm_addr = shmat(shmid, NULL, 0);
  18. pthread_mutex_lock(&m);
  19. //把蜂鸣器的标记位写入共享内存(30-40),共享内存的代码用不着,不用在意
  20. memcpy(shm_addr + 30, beepmanageron, strlen(beepmanageron));
  21. pthread_mutex_unlock(&m);
  22. printf("共享内存内容:%s\n", shm_addr);
  23. // 1. 准备各个模块所需的IPC
  24. mkfifo("/root/fifo", O_CREAT|0666);
  25. mkfifo("/root/led", O_CREAT|0666);
  26. mkfifo("/root/beep", O_CREAT|0666);
  27. mkfifo("/root/ledstat", O_CREAT|0666);
  28. mkfifo("/root/beepstat", O_CREAT|0666);
  29. mkfifo("/root/setting", O_CREAT|0666);
  30. // 2. 依次启动各个模块
  31. if(fork() == 0)
  32. {
  33. execl("./adc_test", "./adc_test", NULL);
  34. }
  35. if(fork() == 0)
  36. {
  37. execl("./buzzer", "./buzzer", NULL);
  38. }
  39. if(fork() == 0)
  40. {
  41. execl("./bt_test", "./bt_test" , NULL);
  42. }
  43. if(fork() == 0)
  44. {
  45. execl("./led_test", "led_test", NULL);
  46. }
  47. // 分离共享内存与当前进程,很可惜没弄出来
  48. if (shmdt(shm_addr) == -1) {
  49. perror("shmdt");
  50. return 1;
  51. }
  52. // 删除共享内存对象
  53. if (shmctl(shmid, IPC_RMID, NULL) == -1) {
  54. perror("shmctl");
  55. return 1;
  56. }
  57. pause();
  58. return 0;
  59. }

这是笔者的管理程序,笔者通过execl函数启动其他的子线程,使用具名管道进行通信。如果大家觉得很麻烦,那大可以把所有的.c文件都放在一个文件里面,这样就不需要进程间通信,也不需要弄共享内存这些吃力不讨好的东西,但是问题在于一个.c文件集成了所有的设备代码,会显得很臃肿,而且也不能练习我们学过的各种进程间通信的知识。所以笔者不建议都弄到一个文件。

下面展示笔者弄的各设备模块的代码:

adc_test2.c

  1. #include "head.h"
  2. #define GEC6818_ADC_IN0 _IOR('A', 1, unsigned long)
  3. #define GEC6818_ADC_IN1 _IOR('A', 2, unsigned long)
  4. int sockfd;
  5. //套接字
  6. int recvfd, sendfd, recvfd1;
  7. //这两个数组用来存放灯和凤鸣器的状态
  8. char lednow[6];
  9. char beepnow[6];
  10. //两个信号量,用来让两个更新程序一直等待执行
  11. sem_t lo;
  12. sem_t bo;
  13. sem_t lf;
  14. sem_t bf;
  15. //这个是屏幕显示的方法
  16. void showbitmap(bitmap *bm, int x, int y, char *p)
  17. {
  18. // 直接写指针,不在这里写打开设备,避免重复调用打开
  19. char *q = p + (y*800 + x)*4;
  20. for(int j=0;j<bm->height && j < 480 ;j++)
  21. {
  22. for(int i=0;i<bm->width && i< 800 ;i++)
  23. memcpy(q+(800*4*j)+i*4,bm->map+(bm->width*bm->byteperpixel*j)+
  24. bm->byteperpixel*i,bm->byteperpixel);
  25. }
  26. bzero(bm->map,bm->width*bm->height*bm->byteperpixel);
  27. }
  28. //这个函数用来一直更新灯的状态
  29. void *updateledon(void *arg)
  30. {
  31. while (1)
  32. {
  33. //p操作,如果没有资源就会一直等待
  34. sem_wait(&lo);
  35. strcpy(lednow, "on");
  36. }
  37. }
  38. void *updateledoff(void *arg)
  39. {
  40. while (1)
  41. {
  42. //p操作,如果没有资源就会一直等待
  43. sem_wait(&lf);
  44. strcpy(lednow, "off");
  45. }
  46. }
  47. //这个函数用来一直更新蜂鸣器的状态
  48. void *updatebeepon(void *arg)
  49. {
  50. while (1)
  51. {
  52. //p操作,如果没有资源就会一直等待
  53. sem_wait(&bo);
  54. strcpy(beepnow, "on");
  55. }
  56. }
  57. void *updatebeepoff(void *arg)
  58. {
  59. while (1)
  60. {
  61. //p操作,如果没有资源就会一直等待
  62. sem_wait(&bf);
  63. strcpy(beepnow, "off");
  64. }
  65. }
  66. //用来接收云端发送过来的警报指令
  67. void *recvudp1(void *arg)
  68. {
  69. //打开led具名管道,把读到的云端命令写到管道里面
  70. int beepfd = open("/root/fifo", O_RDWR);
  71. int setting = open("/root/setting", O_RDWR | O_NONBLOCK);
  72. if(beepfd == -1 || setting == -1)
  73. {
  74. perror("打开BEEP和setting具名管道失败!");
  75. exit(0);
  76. }
  77. //准备好本机的ip
  78. struct sockaddr_in addr = {0};
  79. addr.sin_family = AF_INET;
  80. //当一个服务器程序需要绑定到本机的某个ip地址上时,可以使用这个
  81. //表示服务器愿意接受来自任何可用网络接口的连接
  82. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  83. addr.sin_port = htons(50003);
  84. //绑定上面的地址
  85. if(bind(recvfd1, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  86. {
  87. perror("102绑定地址失败!");
  88. }
  89. //等待对方发来的信息
  90. struct sockaddr_in clientAddr;
  91. //用来存放信息
  92. char buf[6];
  93. while (1)
  94. {
  95. bzero(buf, 6);
  96. socklen_t len = sizeof(clientAddr);
  97. bzero(&clientAddr, len);
  98. //等待udp数据
  99. int n = recvfrom(recvfd1, buf, 6, 0,
  100. (struct sockaddr *)&clientAddr, &len);
  101. if (buf[0] == 't')
  102. {
  103. printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  104. ntohs(clientAddr.sin_port),"开警报!");
  105. //把开警报信息写入管道
  106. write(setting, "on", 2);
  107. usleep(200*1000);
  108. write(beepfd, "on", 2);
  109. sem_post(&bo);
  110. }else if (buf[0] == 'f')
  111. {
  112. printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  113. ntohs(clientAddr.sin_port),"关警报!");
  114. //把关灯信息写入管道
  115. write(beepfd, "off", 3);
  116. write(setting, "off", 3);
  117. sem_post(&bf);
  118. }else{
  119. printf("与云端[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  120. ntohs(clientAddr.sin_port),"通信良好!");
  121. }
  122. }
  123. }
  124. //用来接收云端发送过来的灯指令
  125. void *recvudp(void *arg)
  126. {
  127. //打开led具名管道,把读到的云端命令写到管道里面
  128. int ledfd = open("/root/led", O_RDWR);
  129. if(ledfd == -1)
  130. {
  131. perror("打开LED具名管道失败!");
  132. exit(0);
  133. }
  134. //准备好本机的ip
  135. struct sockaddr_in addr = {0};
  136. addr.sin_family = AF_INET;
  137. //当一个服务器程序需要绑定到本机的某个ip地址上时,可以使用这个
  138. //表示服务器愿意接受来自任何可用网络接口的连接
  139. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  140. addr.sin_port = htons(50002);
  141. //绑定上面的地址
  142. if(bind(recvfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  143. {
  144. perror("154绑定地址失败!");
  145. }
  146. //打开显示设备,实现把状态信息显示到屏幕上
  147. //等待对方发来的信息
  148. struct sockaddr_in clientAddr;
  149. //用来存放信息
  150. char buf[6];
  151. while (1)
  152. {
  153. bzero(buf, 6);
  154. socklen_t len = sizeof(clientAddr);
  155. bzero(&clientAddr, len);
  156. //等待udp数据
  157. int n = recvfrom(recvfd, buf, 6, 0,
  158. (struct sockaddr *)&clientAddr, &len);
  159. if (buf[0] == 't')
  160. {
  161. printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  162. ntohs(clientAddr.sin_port),"开灯!");
  163. //把开灯信息写入管道
  164. write(ledfd, "on", 2);
  165. sem_post(&lo);
  166. }else if (buf[0] == 'f')
  167. {
  168. printf("收到来自云端的命令[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  169. ntohs(clientAddr.sin_port),"关灯!");
  170. //把关灯信息写入管道
  171. write(ledfd, "off", 3);
  172. sem_post(&lf);
  173. }else{
  174. printf("与云端[%s:%hu]:%s\n", inet_ntoa(clientAddr.sin_addr),
  175. ntohs(clientAddr.sin_port),"通信良好!");
  176. }
  177. }
  178. }
  179. //设置一个互斥锁, 本来是用来控制读写共享内存的,结果没弄出来,所以不必在意
  180. pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  181. pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
  182. int main(int argc, char **argv)
  183. {
  184. //打开设备
  185. int lcd = open("/dev/fb0",O_RDWR);
  186. if (lcd == -1)
  187. {
  188. perror("打开屏幕设备错误!");
  189. exit(0);
  190. }
  191. // 获取屏幕属性
  192. struct fb_var_screeninfo fixinfo;
  193. ioctl(lcd,FBIOGET_VSCREENINFO,&fixinfo);
  194. unsigned long VWIDTH = fixinfo.xres; //可见区宽度(单位:像素)
  195. unsigned long VHEIGHT = fixinfo.yres; //可见区高度(单位:像素)
  196. unsigned long BPP = fixinfo.bits_per_pixel; //色深
  197. char *p = mmap(NULL, VWIDTH * VHEIGHT * BPP/8, PROT_WRITE,
  198. MAP_SHARED, lcd, 0);
  199. bzero(p,VWIDTH*VHEIGHT*BPP/8);
  200. //1.初始化字库
  201. font *f1 = fontLoad("simfang.ttf"); // 指定字库文件,比如simfang.ttf
  202. font *f2 = fontLoad("simfang.ttf");
  203. font *f3 = fontLoad("simfang.ttf");
  204. font *f4 = fontLoad("simfang.ttf");
  205. //2.设置字体的大小
  206. fontSetSize(f1, 40);
  207. fontSetSize(f2, 70);
  208. fontSetSize(f3, 60);
  209. fontSetSize(f4, 60);
  210. //3.设置指针指向分配框区域
  211. bitmap *bm1;
  212. bitmap *bm2;
  213. bitmap *bm3;
  214. bitmap *bm4;
  215. //4.给分配框设置不同的大小,因为第三块用来显示通知文本,所以分了200行
  216. bm1 = createBitmapWithInit(800, 50, 4, 0x00000000);
  217. bm2 = createBitmapWithInit(800, 200, 4, 0x00000000);
  218. bm3 = createBitmapWithInit(800, 100, 4, 0x00000000);
  219. bm4 = createBitmapWithInit(800, 100, 4, 0x00000000);
  220. int fd=-1;
  221. int rt;
  222. int i=0;
  223. unsigned long adc_vol = 0;
  224. //初始化信号量,设置为0
  225. sem_init(&lo, 0, 0);
  226. sem_init(&bo,0, 0);
  227. sem_init(&lf, 0, 0);
  228. sem_init(&bf,0, 0);
  229. // 创建SHM对象或者打开
  230. int shmid = shmget(key, 40, IPC_CREAT|0666);
  231. if (shmid == -1) {
  232. perror("shmget");
  233. return 1;
  234. }
  235. //映射共享内存
  236. char *shm_addr = shmat(shmid, NULL, 0);
  237. //创建一个套接字
  238. sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  239. recvfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  240. recvfd1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  241. //sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  242. if (sockfd == -1 ||recvfd == -1 || recvfd1 == -1)
  243. {
  244. perror("创建套接字失败!");
  245. }
  246. //创建两个线程,一个运行发送,一个运行接收
  247. pthread_t t1,t2,t3,t4,t5,t6;
  248. pthread_create(&t1, NULL, recvudp, NULL);
  249. pthread_create(&t2, NULL, recvudp1, NULL);
  250. pthread_create(&t3, NULL, updateledon, NULL);
  251. pthread_create(&t4, NULL, updateledoff, NULL);
  252. pthread_create(&t5, NULL, updatebeepon, NULL);
  253. pthread_create(&t6, NULL, updatebeepoff, NULL);
  254. //准备好对端的ip
  255. struct sockaddr_in addr;
  256. socklen_t len = sizeof(addr);
  257. bzero(&addr, len);
  258. addr.sin_family = AF_INET;
  259. addr.sin_addr.s_addr = inet_addr("192.168.2.10");
  260. addr.sin_port = htons(50001);
  261. //打开adc设备
  262. fd = open("/dev/adc_drv", O_RDWR);
  263. if(fd < 0)
  264. {
  265. perror("open /dev/adc_drv:");
  266. return fd;
  267. }
  268. //弄一个具名管道,把读到的数据写到管道里面
  269. int fifofd = open("/root/fifo", O_RDWR);
  270. //这两个管道用来更新灯和蜂鸣器的状态
  271. int ledstat = open("/root/ledstat", O_RDONLY | O_NONBLOCK);
  272. int beepstat = open("/root/beepstat", O_RDONLY | O_NONBLOCK);
  273. int setting = open("/root/setting", O_RDONLY | O_NONBLOCK);
  274. if(fifofd == -1 || ledstat == -1 || beepstat == -1)
  275. {
  276. perror("打开具名管道失败!");
  277. exit(0);
  278. }
  279. unsigned long n = 0;
  280. //设置一个字符数组用于存放adc数据
  281. char msg[10];
  282. char led[6];
  283. char beep[6];
  284. char ledmsg[6];
  285. char beepmsg[6];
  286. //这个字符串用来存储ADC数据
  287. char BUF1[100];
  288. bzero(BUF1,100);
  289. //这个字符串用来存储灯状态
  290. char BUF2[100];
  291. bzero(BUF2,100);
  292. //这个字符串用来存储蜂鸣器的状态
  293. char BUF3[50];
  294. bzero(BUF3,50);
  295. //读取共享内存内的灯和蜂鸣器状态
  296. pthread_mutex_lock(&m);
  297. memcpy(led, shm_addr + 20, 6);
  298. memcpy(beep, shm_addr + 20, 6);
  299. pthread_mutex_unlock(&m);
  300. while(1)
  301. {
  302. //显示系统时间
  303. time_t t; //获取系统时间
  304. struct tm *Time;
  305. time(&t);
  306. char buf[50]; //定义buf缓冲区,用来存放时间数据
  307. bzero(buf,50);
  308. Time=localtime(&t);
  309. char *wd[7] = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
  310. //把要输出的数据保存到缓冲区buf
  311. snprintf(buf,50,"%d年%d月%d日 %s %d时%d分%d秒",(1900+Time->tm_year),
  312. (1+Time->tm_mon),(Time->tm_mday),
  313. wd[Time->tm_wday],(Time->tm_hour),
  314. Time->tm_min,Time->tm_sec);
  315. //这些数组是暂时用来存放管道里面的数据的
  316. bzero(msg, 10);
  317. bzero(ledmsg, 6);
  318. bzero(beepmsg, 6);
  319. //读取管道内的数据
  320. read(ledstat, ledmsg, 6);
  321. read(beepstat, beepmsg, 6);
  322. //读取ADC通道0的电压值
  323. rt=ioctl(fd,GEC6818_ADC_IN0,&adc_vol);
  324. if(strcmp(ledmsg, "on") == 0)
  325. {
  326. //让灯更新为开
  327. sem_post(&lo);
  328. }
  329. if(strcmp(ledmsg, "off") == 0)
  330. {
  331. //让灯更新为关
  332. sem_post(&lf);
  333. }
  334. if(strcmp(beepmsg, "on") == 0)
  335. {
  336. //让蜂鸣器状态更新为开
  337. sem_post(&bo);
  338. }
  339. if(strcmp(beepmsg, "off") == 0)
  340. {
  341. //让蜂鸣器状态更新为关
  342. sem_post(&bf);
  343. }
  344. if(rt != 0)
  345. {
  346. printf("adc in0 read filed\r\n");
  347. usleep(50*1000);
  348. continue;
  349. }
  350. unsigned long m1 = adc_vol + n;
  351. if(m1 >= 3000 && m1 <= 3100)
  352. {
  353. //把数据写到具名管道
  354. write(fifofd, "on", 2);
  355. n = n + 100;
  356. }
  357. if (m1 > 3500)
  358. {
  359. n = 0;
  360. }
  361. if (m1 >800 && m1 <3000)
  362. {
  363. n = n + 100;
  364. }
  365. if (m1 > 3100)
  366. {
  367. n = n + 100;
  368. }
  369. //把数据写入msg
  370. snprintf(msg, sizeof(msg), "%lu", m1);
  371. //发送数据
  372. int n = sendto(sockfd, msg, strlen(msg), 0,
  373. (struct sockaddr *)&addr, sizeof(addr));
  374. //发送led灯的状态数据
  375. int n1 = sendto(sockfd, lednow, strlen(lednow), 0,
  376. (struct sockaddr *)&addr, sizeof(addr));
  377. //发送蜂鸣器的状态数据
  378. int n2 = sendto(sockfd, beepnow, strlen(beepnow), 0,
  379. (struct sockaddr *)&addr, sizeof(addr));
  380. if(n == -1)
  381. {
  382. perror("发送adc数据失败!");
  383. }
  384. if(n1 == -1)
  385. {
  386. perror("发送led数据失败!");
  387. }else
  388. {
  389. printf("发送成功!");
  390. }
  391. if(n2 == -1)
  392. {
  393. perror("发送beep数据失败!");
  394. }
  395. printf("温度: %lu mv\r\n",m1);
  396. // 从共享内存中读取数据
  397. // printf("共享内存内容:%s\n", shm_addr);
  398. printf("灯状态:%s\n", (strcmp(lednow, "on") == 0) ? "开" : "关");
  399. printf("蜂鸣器状态:%s\n", (strcmp(beepnow, "on") == 0) ? "开" : "关");
  400. //把要输出的内容显示到显示屏上,50表示x的偏移量,5表示距离上一个分配框的距离
  401. //把adc数据写入BUF0
  402. snprintf(BUF1, 100, "ADC值:%lu", m1);
  403. snprintf(BUF2, 100, "灯状态:%s\n", (strcmp(lednow, "on") == 0) ? "开" : "关");
  404. snprintf(BUF3, 50, "蜂鸣器状态:%s\n", (strcmp(beepnow, "on") == 0) ? "开" : "关");
  405. fontPrint(f1, bm1 ,50 ,5,buf, 0x00FFFF00, 0);
  406. fontPrint(f2, bm2, 5,40, BUF1, 0xFF000000, 0);
  407. fontPrint(f4, bm3,100,5, BUF2, 0xFF33CC66,750);
  408. fontPrint(f3, bm4,100,40, BUF3, 0xFFD70000, 0);
  409. //bm妥善地放置到LCD上显示出来
  410. showbitmap(bm1, 10, 0, p);
  411. showbitmap(bm2, 200, 50, p);
  412. showbitmap(bm3, 100, 200, p);//为了让文本有一种居中对齐的效果,所以右边偏移量也-200
  413. showbitmap(bm4, 100, 270, p);
  414. sleep(1);
  415. }
  416. // 分离共享内存与当前进程
  417. if (shmdt(shm_addr) == -1) {
  418. perror("shmdt");
  419. return 1;
  420. }
  421. // 删除共享内存对象
  422. if (shmctl(shmid, IPC_RMID, NULL) == -1) {
  423. perror("shmctl");
  424. return 1;
  425. }
  426. close(fd);
  427. return 0;
  428. }

这个adc_test2.c里面集成了控制蜂鸣器开关的代码,集成了接收云端命令控制led灯开关和蜂鸣器开关的代码,还整合了所有的设备信息向ubuntu发送的功能,还有在lcd上显示设备信息的功能,所以代码比较长,大家仅供参考。

buzzer.c代码:

  1. #include "head.h"
  2. #define BUZZER_IOCTL_SET_FREQ 1
  3. #define BUZZER_IOCTL_STOP 0
  4. void Usage(char *args)
  5. {
  6. printf("Usage: %s <on/off> <freq>\n",args);
  7. return ;
  8. }
  9. //定义一个全局变量
  10. int buzzer_fd;
  11. //设置一个匿名POSIX信号量用来控制线程运行
  12. sem_t s;
  13. sem_t bt;
  14. //设置一个互斥锁
  15. pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  16. //设置蜂鸣器的标记位
  17. const char *beepmanageron = "true";
  18. const char *beepmanageroff = "false";
  19. //蜂鸣器状态
  20. const char *beepstaton = "on";
  21. const char *beepstatoff = "off";
  22. //设置一个函数,用来关闭蜂鸣器
  23. void *shutdownbeep(void *arg)
  24. {
  25. //这个管道用来更新蜂鸣器的状态
  26. int beepstat1 = open("/root/beepstat", O_RDWR);
  27. while (1)
  28. {
  29. sem_wait(&bt);
  30. ioctl(buzzer_fd, BUZZER_IOCTL_STOP, 2000);
  31. write(beepstat1, "off", 3);
  32. }
  33. }
  34. //设置一个函数,用来设置蜂鸣器的声音频率
  35. void *beepAlarm(void *arg)
  36. {
  37. //这个管道用来更新蜂鸣器的状态
  38. int beepstat1 = open("/root/beepstat", O_RDWR);
  39. while (1)
  40. {
  41. //p操作,如果没有资源就会一直等待
  42. sem_wait(&s);
  43. ioctl(buzzer_fd, BUZZER_IOCTL_SET_FREQ, 2000);
  44. usleep(200*1000);
  45. //ioctl(buzzer_fd, BUZZER_IOCTL_STOP, 2000);
  46. usleep(200*1000);
  47. write(beepstat1, "on", 2);
  48. }
  49. }
  50. int main(int argc , char **argv)
  51. {
  52. // 创建SHM对象或者打开
  53. int shmid = shmget(key, 40, 0644|IPC_CREAT);
  54. if (shmid == -1) {
  55. perror("shmget");
  56. return 1;
  57. }
  58. //映射共享内存
  59. char *shm_addr = shmat(shmid, NULL, 0);
  60. //初始化信号量,设置为0
  61. sem_init(&s, 0, 0);
  62. sem_init(&bt,0, 0);
  63. unsigned long freq = 0;
  64. char *endstr, *str;
  65. buzzer_fd = open("/dev/pwm", O_RDWR);
  66. if(buzzer_fd < 0)
  67. {
  68. perror("打开设备失败:");
  69. exit(1);
  70. }
  71. //创建线程,以便于运行蜂鸣器
  72. pthread_t t, k;
  73. pthread_create(&t, NULL, beepAlarm, NULL);
  74. pthread_create(&k, NULL, shutdownbeep, NULL);
  75. //打开具名管道
  76. int fifofd = open("/root/fifo", O_RDWR);
  77. int beepsetting = open("/root/setting", O_RDWR | O_NONBLOCK);
  78. //用一个字符数组来存放读到的数据
  79. char buf[5];
  80. char set[5];
  81. //这个是蜂鸣器的开关标记位
  82. int setting = 1;
  83. while (1)
  84. {
  85. bzero(buf, 5);
  86. bzero(set, 5);
  87. read(fifofd, buf, 5);
  88. read(beepsetting, set, 5);
  89. // 从共享内存的第30个字节到第40个字节之间读取蜂鸣器的标记
  90. char beepsingal[6];
  91. pthread_mutex_lock(&m);
  92. memcpy(beepsingal, shm_addr + 30, 6);
  93. pthread_mutex_unlock(&m);
  94. if(strcmp(set, "off")==0)
  95. {
  96. setting = 0;
  97. }
  98. if(strcmp(set, "on")==0)
  99. {
  100. setting = 1;
  101. }
  102. //如果读到on,就执行v操作
  103. if(strcmp(buf, "on")==0 /*&& strcmp(beepsingal, "true") == 0*/)
  104. {
  105. if(setting == 1)
  106. {
  107. sem_post(&s);
  108. }
  109. // printf("worning!\n");
  110. pthread_mutex_lock(&m);
  111. //蜂鸣器状态设置为开
  112. memcpy(shm_addr + 20, beepstaton, strlen(beepstaton));
  113. pthread_mutex_unlock(&m);
  114. }
  115. if(strcmp(buf, "off") == 0)
  116. {
  117. //让关蜂鸣器程序开启
  118. sem_post(&bt);
  119. }
  120. if(strcmp(buf, "bpon") == 0)
  121. {
  122. //蜂鸣器状态设置为开,也把蜂鸣器的标记位设置为true
  123. sem_post(&s);
  124. }
  125. }
  126. // 分离共享内存与当前进程,下面这两个代码都是用不到的,为了避免删除后会发生未知错误,我就不动他们了
  127. if (shmdt(shm_addr) == -1) {
  128. perror("shmdt");
  129. return 1;
  130. }
  131. // 删除共享内存对象
  132. if (shmctl(shmid, IPC_RMID, NULL) == -1) {
  133. perror("shmctl");
  134. return 1;
  135. }
  136. close(buzzer_fd);
  137. return 0;
  138. }

这个是蜂鸣器的控制代码,里面的逻辑仅供参考,共享内存相关的代码不用理会,因为作者一开始想用共享内存记录各种设备的状态,结果没弄出来,遇到了一些不可控的错误,后面笔者改用管道了,大家也可以用消息队列,不一定要用管道。

led_test.c代码:

  1. #include "head.h"
  2. #define TEST_MAGIC 'x'
  3. #define TEST_MAX_NR 2
  4. //每个led灯的控制
  5. #define LED1 _IO(TEST_MAGIC, 0)
  6. #define LED2 _IO(TEST_MAGIC, 1)
  7. #define LED3 _IO(TEST_MAGIC, 2)
  8. #define LED4 _IO(TEST_MAGIC, 3)
  9. //设置信号量
  10. sem_t s;
  11. sem_t s1;
  12. int fd;
  13. const char *ledison = "on";
  14. const char *ledisoff = "off";
  15. //共享内存的东西,不用管
  16. pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
  17. void *ledon(void *arg)
  18. {
  19. char *shm_addr = (char *)arg;
  20. while(1)
  21. {
  22. sem_wait(&s);
  23. pthread_mutex_lock(&m);
  24. ioctl(fd, LED1, 0);
  25. ioctl(fd, LED2, 0);
  26. ioctl(fd, LED3, 0);
  27. ioctl(fd, LED4, 0);
  28. // 共享内存的东西,不用管
  29. memcpy(shm_addr + 10, ledison, strlen(ledison));
  30. pthread_mutex_unlock(&m);
  31. }
  32. }
  33. //控制灯开
  34. void *ledoff(void *arg)
  35. {
  36. char *shm_addr = (char *)arg;
  37. while(1)
  38. {
  39. sem_wait(&s1);
  40. pthread_mutex_lock(&m);
  41. ioctl(fd, LED1, 1);
  42. ioctl(fd, LED2, 1);
  43. ioctl(fd, LED3, 1);
  44. ioctl(fd, LED4, 1);
  45. memcpy(shm_addr + 10, ledisoff, strlen(ledisoff));
  46. pthread_mutex_unlock(&m);
  47. }
  48. }
  49. int main(int argc, char **argv)
  50. {
  51. // 共享内存,不用管
  52. int shmid = shmget(key, 40, IPC_CREAT|0666);
  53. if (shmid == -1) {
  54. perror("shmget");
  55. return 1;
  56. }
  57. //不必理会
  58. char *shm_addr = shmat(shmid, NULL, 0);
  59. // 控制灯开
  60. sem_init(&s, 0, 0);
  61. sem_init(&s1, 0, 0);
  62. //共享内存不必理会
  63. pthread_t t1, t2;
  64. pthread_create(&t1, NULL, ledon, (void*)shm_addr);
  65. pthread_create(&t2, NULL, ledoff, (void*)shm_addr);
  66. fd = open("/dev/Led",O_RDWR); //���豸�µ�LED���ɹ�����0
  67. if(fd<0)
  68. {
  69. perror("Can not open /dev/LED\n");
  70. return 0;
  71. }
  72. //打开具名管道,把灯的状态写进去
  73. int fifofd = open("/root/led", O_RDWR);
  74. //��һ���ַ���������Ŷ�ȡ����led����
  75. char buf[5];
  76. while (1)
  77. {
  78. bzero(buf, 5);
  79. read(fifofd, buf, 5);
  80. if (strcmp(buf, "on") == 0)
  81. {
  82. //v�������������on�ͻ��һ���ź���
  83. sem_post(&s);
  84. }else{
  85. //����off�ͻ���صƳ����һ���ź���
  86. sem_post(&s1);
  87. }
  88. }
  89. // ���빲���ڴ��뵱ǰ����
  90. if (shmdt(shm_addr) == -1) {
  91. perror("shmdt");
  92. return 1;
  93. }
  94. // ɾ�������ڴ����
  95. if (shmctl(shmid, IPC_RMID, NULL) == -1) {
  96. perror("shmctl");
  97. return 1;
  98. }
  99. close(fd);
  100. return 0;
  101. }

这乱码不用管,看得懂代码逻辑即可,笔者也不知道怎么回事突然乱码了(TvT)。

好了,以上就是用得到的模块的代码了,至于显示状态在LCD屏幕上,那肯定需要用得到字库跟lcd,已经是用的很熟悉了,笔者就不再赘述,上面所有的模块代码都只是仅供参考,因为每一个人的思路不一样,我这也只是其中的一种。头文件我没给出,如果大家需要设备端的源码,可以从我的百度云盘提取:链接:百度网盘 请输入提取码

提取码:zlw6

二、总结

        总的来说整个项目并不难,难的是一开始你没有经验,然后不知道该做什么,怎么做。所以一开始确定方向很重要,你需要把整个项目的思路理清楚,才能按照你的思路做下去,打通SDK与Ubuntu的联系并不难,难的是如果你需要从云端发送命令控制设备端,就需要对SDK的源码进行修改,其中有很多你需要摸索的函数,该如何使用他们。SDK提供了很多函数,在你使用不同的数据类型发送命令的时候,也会用到不同的函数。笔者自己修改SDK的源码实现命令下发判断的时候,就踩了很多坑,后面才和伙伴一起摸索出来,“哦,原来用这个函数才可以”。所以,没有一个项目是一帆风顺的,趁现在还在学习,多踩一点坑,以后工作的时候就会少踩一点坑。

        在整个项目中,笔者使用的是UDP进行ubuntu对云端命令的转发,以及开发板向ubuntu发送设备数据,因为数据量不大,所以UDP就够了,而且ubuntu也是5秒才上传一次数据到云端,就算UDP一两次的数据丢了也不要紧。如果大家要实现tcp通信,也可以在SDK的main函数里创建套接字进行实现。

最后提供笔者的AgentLiteDemo.c的main函数作参考

  1. int main(int argc, char **argv)
  2. {
  3. #if defined(_DEBUG)
  4. setvbuf(stdout, NULL, _IONBF, 0); //in order to make the console log printed immediately at debug mode
  5. #endif
  6. //创建两个套接字
  7. //recvfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  8. sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  9. if (sendfd == -1)
  10. {
  11. perror("创建套接字失败!");
  12. exit(0);
  13. }
  14. // 信号量初始化
  15. sem_init(&s, 0, 0);
  16. sem_init(&xf,0, 1);
  17. sem_init(&bp,0, 1);
  18. IOTA_SetPrintLogCallback(myPrintLog);
  19. setConnectConfig();
  20. printfLog(EN_LOG_LEVEL_INFO, "AgentLiteDemo: start test ===================>\n");
  21. if (IOTA_Init(workPath) > 0)
  22. {
  23. printfLog(EN_LOG_LEVEL_ERROR, "AgentLiteDemo: IOTA_Init() error, init failed\n");
  24. return 1;
  25. }
  26. setAuthConfig();
  27. setMyCallbacks();
  28. //see handleLoginSuccess and handleLoginFailure for login result
  29. int ret = IOTA_Connect();
  30. if (ret != 0)
  31. {
  32. printfLog(EN_LOG_LEVEL_ERROR, "AgentLiteDemo: IOTA_Auth() error, Auth failed, result %d\n", ret);
  33. }
  34. //创建一个线程用来执行udp链接
  35. pthread_t t, t1,t2;
  36. pthread_create(&t, NULL, recvDate, NULL);
  37. pthread_create(&t1, NULL, sendUDP, NULL);
  38. pthread_create(&t2, NULL, sendUDP1, NULL);
  39. //pthread_create(&t2, NULL, recvudp, NULL);
  40. timeSleep(1500);
  41. int count = 0;
  42. while(count < 10000)
  43. {
  44. // //message up
  45. // Test_messageReport();
  46. //properties report
  47. Test_propertiesReport();
  48. // //batchProperties report
  49. // Test_batchPropertiesReport();
  50. //
  51. // //command response
  52. // Test_commandResponse("1005");
  53. //
  54. // timeSleep(1500);
  55. //
  56. // //propSetResponse
  57. // Test_propSetResponse("1006");
  58. //
  59. // timeSleep(1500);
  60. //
  61. // //propSetResponse
  62. // Test_propGetResponse("1007");
  63. timeSleep(sleepTime);
  64. count++;
  65. }
  66. while (1)
  67. {
  68. timeSleep(50);
  69. }
  70. return 0;
  71. }

        这个项目笔者耗时5天才全部弄完并把全部的功能实现,费时间的主要在前期弄共享内存,后面弄了好久居然发现用不了,又被迫用回管道这种简单粗暴的方式,在此先祝大家项目成功,希望我的文档对大家有帮助,谢谢大家。

笔者版本:

Ubuntu20.04 windows11 VMware17

后记:

        如果还有小伙伴是完全不会弄这个项目的,我在百度网盘存放了整个项目需要用到的各种驱动,还有源码,还有修改过的SDK文件以及我的演示视频,大家可以自行提取,但是不可用直接运行,因为每个人华为云上的设备号都不一样的,还有ip地址也需要修改。

链接:https://pan.baidu.com/s/1C_5E-uOJlV59EGKkQxRijg 
提取码:zlw6

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/163901
推荐阅读
相关标签
  

闽ICP备14008679号