手机短信管理系统及设备通信协议_第1页
手机短信管理系统及设备通信协议_第2页
手机短信管理系统及设备通信协议_第3页
手机短信管理系统及设备通信协议_第4页
手机短信管理系统及设备通信协议_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

宜宾学院课程设计文档课程软件编程实践题目手机短信管理系统院别计算机与信息工程学院专业软件工程学生姓名学号班级20XX级授课教师目录第1章系统总体设计 图4-1主函数流程图图4-1主函数流程图程序截图图4-1图4-1主界面流程图图4-2主界面截图源代码/*项目名称:手机短信管理系统实施时间:20XX年12月22日创建人:郭成*///调用预处理#include"stdio.h"//标准输入输出#include"stdlib.h"//常用的系统函数//函数声明voidAddressbookmenu();//通讯录voidMessagemenu();//短信//主函数voidmain(){ charfilename[20];//文件名变量 inti; system("title手机短信管理系统");//设置cmd窗口标题system("color3B");//背景湖蓝,字体白 do { system("cls");//清屏 printf("nowdatetime:\n"); system("date/T");//调用系统日期system("TIME/T");//调用系统时间 printf("\n\n\n"); printf("\n\t\t\t\n"); printf("\t\t\t*==============手机短信管理系统==============*\n"); printf("\n\t\t\t\n"); printf("\t\t**\n"); printf("\t\t***1.通讯录***\n"); printf("\t\t***2.短信***\n"); printf("\t\t**\n"); printf("\t\t********************\n"); printf("\t\t***0.退出系统***\n"); printf("\t\t**************\n"); printf("\n\t\t\t\n"); printf("\t\t\tYIBIN printf("\n\t\t\t\n"); scanf("%d",&i); switch(i) { case1:system("cls");Addressbookmenu();break;//case1调用addressbookmenu函数 case2:system("cls");Messagemenu();break;//case2调用messagemenu函数 case0:break;//case0退出 default:printf("错误选择!请重选");break; //default:break;一般用在switch语句里面,它的作用是在比较i和下面的1、2之后都不一致就执行。当然如果都不满足也可以不去做任何事,所以就可以省略不用 } }while(i!=0);//当i不等于0循环}通讯录流程图开始开始读出功能代号添加删除修改查看显示关闭123456结束退出通讯录(图4-3)通讯录流程图添加功能:录入新的联系人数据,姓名、电话号码、类型、邮箱。开始开始读入编号录入数据录入数据失败返回主菜单保存编号重复YN录入成功YN(图4-4)添加功能流程图删除功能:输入编号,对其信息进行删除。开始开始读入编号删除删除失败返回主菜单保存有此编号NY(图4-4)删除功能流程图修改功能:输入编号,对其信息进行修改。开始开始读入编号修改修改失败返回主菜单保存有此编号NY(图4-5)修改功能流程图查看:输入编号,显示出此编号的姓名、电话号码、类型、邮箱。开始开始打开文件输入编号没有此编号返回主菜单显示信息有此编号NY(图4-6)显示功能流程图程序截图(图4-7)通讯录主界面截图(图4-8)添加功能截图(图4-9)修改功能截图(图4-10)显示功能截图源代码/*项目名称:手机短信管理系统实施时间:20XX年12月22日创建人:郭成*/#include"stdio.h"#include"stdlib.h"#include"string.h"//定义结构体类型typedefstructPatient_Info//typedef自定义结构体类型PatientInfo,可以用PatientInfo来定义变量{ intnumber;//编号 charname[8];//姓名 charphonecode[20];//电话号码 chargroup[10];//类型 charemail[20];//邮箱 charcontent[200];//短信内容}PatientInfo;//局部函数声明staticvoidInsert(char[]);staticvoidSearch(char[]);staticvoidUpdate(char[]);staticvoidDelete(char[]);staticvoidShow(char[]);//主菜单voidAddressbookmenu(){ charfilename[20];//文件名变量 inti; charAdd[]="Addressbook.dll";//指定文件 strcpy(filename,Add); do { printf("\nnowdatetime:\n"); system("date/T");system("TIME/T"); printf("\n\n\n"); printf("\t\t*==============手★机★通★讯★录★管★理★系★统==============*\n"); printf("\t\t**\n"); printf("\t\t*1.添加联系人2.删除联系人*\n"); printf("\t\t*3.修改联系人4.查看联系人*\n"); printf("\t\t*5.显示所有联系人6.关闭通讯录*\n"); printf("\t\t**\n"); printf("\t\t********************\n"); printf("\t\t**请输入序号**\n"); printf("\t\t********************\n"); printf("\t\t*==============================================================*\n"); scanf("%d",&i); fflush(stdin);//清空输入缓存,以便不影响后面输入的东西 switch(i) { case1:system("cls");Insert(filename);break; case2:system("cls");Delete(filename);break; case3:system("cls");Update(filename);break; case4:system("cls");Search(filename);break; case5:system("cls");Show(filename);break; case6:break; default:printf("错误选择!请重选");break; } }while(i!=6);}//添加联系人voidInsert(charFilename[]){ /* 函数说明:对指定文件名进行数据的插入 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:addressbookmenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP;//定义一个信息的变量 intflag=1; FILE*fp; fp=fopen(Filename,"r");//以只读方式打开文件,第一个参数:文件名,第二个参数是打开方式,a表示追加写方式,w表示覆盖写,r表示只读方式,返回值是一个文件指针 printf("请根据以下提示信息操作:"); printf("\n编号:");//先查重,再追加插入 scanf("%d",&in_number); while(!feof(fp)&&flag)//feof表示endoffile,表示文件末尾,true表示文件末尾,否则不是文件末尾。&&flag表示还未查找到 { if(fread(&P,sizeof(PatientInfo),1,fp))/*fread是文件输出函数,从文件中读取一条联系人信息放入P变量中,第一个参数是目标变量的地址, 第二个参数是读取的长度单位,第三个参数是读取几个单位,第四个参数是要读取的文件,返回值为1表示成功,否则表示失败*/ { if(P.number==in_number) { printf("\n该编号已存在,自动取消录入!\n"); flag=0; } } } fclose(fp);//关闭文件以便追加记录 if(flag) { fp=fopen(Filename,"a");//以追加方式打开文件准备追加 } else return; P.number=in_number; printf("请输入姓名:"); scanf("%s",P.name); printf("请输入电话:"); scanf("%s",&P.phonecode); printf("请输入类型:"); printf("存储类别:(A.办公类B.个人类C.商务类)"); scanf("%s",P.group); printf("请输入邮箱:"); fflush(stdin);//清空输入缓存,以便不影响后面输入的东西 scanf("%s",P.email);printf("\n"); if(fwrite(&P,sizeof(PatientInfo),1,fp)!=1)/*fwrite是文件写函数,从P变量中向文件中写入一条短信信息,第一个参数是来源变量的地址, 第二个参数是写的长度单位,第三个参数是写几个单位,第四个参数是要写的文件*/ { printf("输入数据失败,请重新输入!"); } else printf("\n添加成功!"); fclose(fp);}voidSearch(charFilename[]){ /* 函数说明:从指定文件中查找数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:addressbookmenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp; fp=fopen(Filename,"r"); printf("\n请根据以下提示信息操作:"); printf("\n编号:"); scanf("%d",&in_number); system("cls"); while(fread(&P,sizeof(PatientInfo),1,fp)&&flag)//fread是文件输出函数,返回值为1表示读成功 { if(P.number==in_number) { printf("\n\t\t\t\n"); printf("\n\t\t\t|编号\t|姓名\t|电话\t\t|类型\t|邮箱\t\t\t|"); printf("\n\t\t\t|%d\t",P.number); printf("%s\t",P.name); printf("%s\t",P.phonecode); printf("%s\t",P.group); printf("%s\t|",P.email); printf("\n\n\t\t\t联系人%s的信息已显示出来!\n",P.name); printf("\t\t\t"); flag=0; } } fclose(fp); if(flag) { printf("没有你要找的联系人!"); }}voidUpdate(charFilename[])//{ /* 函数说明:修改指定文件中的数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:addressbookmenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp,*fptemp;//必须两个文件操作,fp是数据源文件,fptemp是临时文件,修改后的数据临时放入该文件中 fp=fopen(Filename,"r");//文件读 fptemp=fopen("temp.txt","w");//文件写 printf("\n修改联系人信息"); printf("\n请输入你要修改的联系人的编号:");//先查询,再修改 scanf("%d",&in_number); while(fread(&P,sizeof(PatientInfo),1,fp))//文件读 { if(P.number==in_number)//读出修改 { P.number=in_number; printf("请输入姓名:"); scanf("%s",P.name); printf("请输入电话:"); scanf("%s",&P.phonecode); printf("请输入类型:"); printf("存储类别:(A.办公类B.个人类C.商务类)"); scanf("%s",P.group); printf("请输入邮箱:"); fflush(stdin);//清空输入缓存,以便不影响后面输入的东西 scanf("%s",P.email); printf("\n"); flag=0; } fwrite(&P,sizeof(PatientInfo),1,fptemp);/*找没找到都往临时文件中写,因为对文件操作只有追加和覆盖写两种方方式, 因此修改中间某条记录不方便,只能引入第二个文件或者放入数据、链表中*/ printf("\n修改成功!"); } fclose(fp); fclose(fptemp); if(flag) { printf("没有你要查询的结果!"); } else { fptemp=fopen("temp.txt","r");//从临时文件中读 fp=fopen(Filename,"w");//往源文件中覆盖写 while(fread(&P,sizeof(PatientInfo),1,fptemp)) { fwrite(&P,sizeof(PatientInfo),1,fp);//从临时文件中回写 } fclose(fp); fclose(fptemp); }}voidDelete(charFilename[])//{ /* 函数说明:删除指定文件中的某条数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:addressbookmenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp,*fptemp; fp=fopen(Filename,"r"); fptemp=fopen("temp.txt","w"); printf("\n请输入你想要删除的联系人的编号:");//先查询,再删除 scanf("%d",&in_number); while(fread(&P,sizeof(PatientInfo),1,fp)) { if(P.number!=in_number)//如果找到要删除的记录则不写,否则都要写 fwrite(&P,sizeof(PatientInfo),1,fptemp); else flag=0; } fclose(fp); fclose(fptemp); if(flag) { printf("没有你要删除的编号!"); } else { fp=fopen(Filename,"w"); fptemp=fopen("temp.txt","r"); while(fread(&P,sizeof(PatientInfo),1,fptemp)) { fwrite(&P,sizeof(PatientInfo),1,fp); } printf("删除成功!"); fclose(fp); fclose(fptemp); }}voidShow(charFilename[]){ /* 函数说明:显示指定文件中的所有数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:addressbookmenu函数 创建人:郭成 创建日期:12月22日 */ PatientInfoP; intflag=1; FILE*fp; fp=fopen(Filename,"r"); while(fread(&P,sizeof(PatientInfo),1,fp)) { printf("\n\t\t\t\n"); printf("\n\t\t\t|编号\t|姓名\t|电话\t\t|类型\t|邮箱\t\t\t|"); printf("\n\t\t\t|%d\t",P.number); printf("%s\t",P.name); printf("%s\t",P.phonecode); printf("%s\t",P.group); printf("%s\t|",P.email); printf("\n\t\t\t"); } printf("\n\t\t\t所有联系人信息已全部显示出来!\n"); fclose(fp);}短信录流程图开始开始读出功能代号新建删除修改查看显示关闭123456结束关闭短信录(图4-11)短信录主函数流程图 新建功能:在新建短信输入编号时,将判断此编号在通讯录上有无,如果有则显示出来,并对此编号发送信息,如果没有此编号则新建一条信息。开始开始读入编号显示此编号信息发送短信返回主菜单保存编号是否存在NY(图4-12)新建短信流程图(删除、修改、查看、显示流程图均与通讯录相差不大,这里就不画出来了)程序截图(图4-13)短信录主界面截图(图4-14)短信录新建短信截图(图4-15)短信录显示短信截图(图4-16)短信录删除短信截图源代码/*项目名称:手机短信管理系统实施时间:20XX年12月22日创建人:郭成*/#include"stdio.h"#include"stdlib.h"#include"string.h"#include"windows.h"//定义了Windows的所有资料型态、函数调用、资料结构和常数识别字#include"conio.h"//进行输入、输出的//定义结构体类型typedefstructPatient_Info//typedef自定义结构体类型PatientInfo,可以用PatientInfo来定义变量{ intnumber;//编号 charname[8];//姓名 charphonecode[20];//电话号码 chargroup[10];//类型 charemail[20];//邮箱 charcontent[200];//短信内容}PatientInfo;//局部函数声明staticvoidAdd(char[]);staticvoidSearch(char[]);staticvoidAlter(char[]);staticvoidDel(char[]);staticvoidShow(char[]);//主菜单voidMessagemenu(){ inti; charFilename[20];//文件名变量 charMes[]="Message.dll";//指定文件 strcpy(Filename,Mes); do { printf("\nnowdatetime:\n"); system("date/T");system("TIME/T"); printf("\n\n\n"); printf("\t\t*================手★机★短★信★管★理★系★统================*\n"); printf("\t\t**\n"); printf("\t\t*1.新建信息2.删除信息*\n"); printf("\t\t*3.修改信息4.查看联系人*\n"); printf("\t\t*5.显示所有信息6.关闭短信录*\n"); printf("\t\t**\n"); printf("\t\t********************\n"); printf("\t\t**请输入序号**\n"); printf("\t\t********************\n"); printf("\t\t*==============================================================*\n"); scanf("%d",&i); fflush(stdin);//清空输入缓存,以便不影响后面输入的东西 switch(i) { case1:system("cls");Add(Filename);break; case2:system("cls");Del(Filename);break; case3:system("cls");Alter(Filename);break; case4:system("cls");Search(Filename);break; case5:system("cls");Show(Filename);break; case6:break; default:printf("错误选择!请重选");break; } }while(i!=6);}//新建短信voidAdd(charFilename[])//{ /* 函数说明:对指定文件名进行数据的插入 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:messagemenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP;//定义一个信息的变量 intflag=1; FILE*fp,*fptemp;//fp是数据源文件,fptemp是临时文件 fptemp=fopen("Addressbook.dll","r");//已只读方式临时打开通讯录文件,此操作是为了才看通讯录里是否有相同的编号,如果有则显示出来 printf("请根据以下提示信息操作:"); printf("\n编号:"); scanf("%d",&in_number); while(!feof(fptemp)&&flag) { if(fread(&P,sizeof(PatientInfo),1,fptemp)) { if(P.number==in_number) { printf("\n该编号已存在,自动显示该编号联系人!\n"); printf("\n\t\t\t\n"); printf("\n\t\t\t|编号\t|姓名\t|电话\t\t|类型\t|邮箱\t\t\t|"); printf("\n\t\t\t|%d\t",P.number); printf("%s\t",P.name); printf("%s\t",P.phonecode); printf("%s\t",P.group); printf("%s\t|",P.email); printf("\n\n\t\t\t联系人%s的信息已显示出来!\n",P.name); printf("\t\t\t"); } } } fclose(fptemp);//关闭通讯录文件以便短信内容储存在短信文件内 fp=fopen(Filename,"a");//以追加方式打开短信文件准备追加 printf("\n新建短信:\n"); P.number=in_number; printf("姓名:"); scanf("%s",P.name); printf("电话:"); scanf("%s",&P.phonecode); printf("短信内容:"); scanf("%s",P.content); printf("\n\t\t\t"); if(fwrite(&P,sizeof(PatientInfo),1,fp)!=1) { printf("输入数据失败,请重新输入!"); } else printf("\n添加成功!"); fclose(fp);}voidSearch(charFilename[]){ /* 函数说明:从指定文件中查找数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:messagemenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp; fp=fopen(Filename,"r"); printf("\n请根据以下提示信息操作:");//先查重,再追加插入 printf("\n编号:"); scanf("%d",&in_number); system("cls"); while(fread(&P,sizeof(PatientInfo),1,fp)&&flag)//fread是文件输出函数,返回值为1表示读成功 { if(P.number==in_number) { printf("\n\t\t\t\n"); printf("\n\t\t\t|编号\t|姓名\t|电话\t\t|短信内容\t\t\t|"); printf("\n\t\t\t|%d",P.number); printf("|%s\t",P.name); printf("|%s\t",P.phonecode); printf("|%s\t",P.content); printf("\n\n\t\t\t联系人%s的信息已显示出来!\n",P.name); printf("\t\t\t"); flag=0; } } fclose(fp); if(flag) { printf("没有你要找的信息!"); }}voidAlter(charFilename[])//{ /* 函数说明:修改指定文件中的数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:messagemenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp,*fptemp;//必须两个文件操作,fp是数据源文件,fptemp是临时文件,修改后的数据临时放入该文件中 fp=fopen(Filename,"r");//文件读 fptemp=fopen("temp.txt","w");//文件写 printf("\n修改联系人信息"); printf("\n请输入你要修改的联系人的编号:");//先查询,再修改 scanf("%d",&in_number); while(fread(&P,sizeof(PatientInfo),1,fp))//文件读 { if(P.number==in_number)//读出修改 { P.number=in_number; printf("\n姓名:"); scanf("%s",P.name); printf("电话:"); scanf("%s",&P.phonecode); printf("短信内容:"); scanf("%s",P.content); printf("\n\t\t\t"); flag=0; } fwrite(&P,sizeof(PatientInfo),1,fptemp);/*找没找到都往临时文件中写,因为对文件操作只有追加和覆盖写两种方方式, 因此修改中间某条记录不方便,只能引入第二个文件或者放入数据、链表中*/ printf("\n修改成功!"); } fclose(fp); fclose(fptemp); if(flag) { printf("没有你要查询的结果!"); } else { fptemp=fopen("temp.txt","r");//从临时文件中读 fp=fopen(Filename,"w");//往源文件中覆盖写 while(fread(&P,sizeof(PatientInfo),1,fptemp)) { fwrite(&P,sizeof(PatientInfo),1,fp);//从临时文件中回写 } fclose(fp); fclose(fptemp); }}voidDel(charFilename[])//{ /* 函数说明:删除指定文件中的某条数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:messagemenu函数 创建人:郭成 创建日期:12月22日 */ intin_number; PatientInfoP; intflag=1; FILE*fp,*fptemp; fp=fopen(Filename,"r"); fptemp=fopen("temp.txt","w"); printf("\n请输入你想要删除的联系人的编号:");//先查询,再删除 scanf("%d",&in_number); while(fread(&P,sizeof(PatientInfo),1,fp)) { if(P.number!=in_number)//如果找到要删除的记录则不写,否则都要写 fwrite(&P,sizeof(PatientInfo),1,fptemp); else flag=0; } fclose(fp); fclose(fptemp); if(flag) { printf("没有你要删除的编号!"); } else { fp=fopen(Filename,"w"); fptemp=fopen("temp.txt","r"); while(fread(&P,sizeof(PatientInfo),1,fptemp)) { fwrite(&P,sizeof(PatientInfo),1,fp); } printf("删除成功!"); fclose(fp); fclose(fptemp); }}voidShow(charFilename[]){ /* 函数说明:显示指定文件中的所有数据 形参说明:数组作为形参,实参必须是一个地址,用于传递文件名 调用位置:messagemenu函数 创建人:郭成 创建日期:12月22日 */ PatientInfoP; intflag=1; FILE*fp; fp=fopen(Filename,"r"); while(fread(&P,sizeof(PatientInfo),1,fp)) {printf("\n\t\t\t\n"); printf("\n\t\t\t|编号\t|姓名\t|电话\t\t|短信内容\t\t\t|"); printf("\n\t\t\t|%d",P.number); printf("|%s\t",P.name); printf("|%s\t",P.phonecode); printf("|%s\t",P.content); printf("\n\t\t\t"); } printf("\n\t\t\t所以联系人的信息已显示出来!\n"); fclose(fp);}总结经过二个周的程序设计实验,我清楚并且深刻地认识到了编写一个计算机程序的不易。要成功实现一个C程序的编译与运行,前提是熟练掌握C语言中基本的命令指示符,并且要能熟练运用各种语句结构及算法。其次,好的开始才能带动一个好的过程,一个程序的设计离不开一个清晰的逻辑框架和程序模块,同时也需要我们严格并有条理地按照既有的设计思路来进行代码的编写。代码的编写对我来说可以说是最大的一道坎,对于只有一学期C语言学习经历的我来说,要编写这么庞大复杂的程序是几乎是不可能的,但是,在代码编写过程中我不断学习,不断去想那些师兄问问题,找同学互相学习,终于把代码基本编写了出来。最后,程序的调试也是个极其困难的过程,要么是语法错误,要么修改后有些功能实现不了,那些简单的语法错误我们改正还比较容易,功能实现的问题就比较困难了,我还得四处搜集资料,或者请教老师和一些水平比较高的同学。一门技术的理论学习是辛苦的,但要懂得一门技术的运用更要付出劳动和汗水。虽然我的程序还有很多欠缺,比如,当删除或修改通讯录中一个人的信息后,他在短信录中的信息还是没变,但最后我还是值得高兴,就像自己完成了一个奇迹一样,做了一件自己一个人几乎不可能完成的任务,那种成就感无法用语言表达。虽然程序设计困难重重,但我都坚持了下来。这两周的实验也让我明白,虽然自己手中的手机玩起来很容易,但其实手机的背后是多大的人力物力的堆积啊,这都是现代科技的成果!总而言之,这两周的实验让我收益匪浅。它不仅将理论与实际相结合,培养了我动手操作和独立思考的能力,为我以后步入社会做准备。这次的实验激发了我不断学习兴趣,它让还我明白了,不论困难多大,只要我们积极思考,勇于实践,就一定能够解决问题。设备通信协议目录TOC\o"1-3"1. 适用范围 22. 协议框架 23. 协议内容 23.1设备内部组网协议(或者MCU透传模式协议) 23.1.1通讯命令格式 23.1.2配对机制 23.1.3连接机制 33.1.4心跳机制 43.2设备与云端通讯协议 43.2.1通讯命令格式 43.2.2连接流程 43.3数据包格式定义 53.3.1 设备间通讯数据格式 53.3.2设备与云、APP通讯数据格式 104. 公共命令定义 115. 编码表 185.1节点类型编码表 185.2命令回应编码表 18

适用范围本协议定义WiFi模块与MCU控制单元,WiFi模块与云APP间,以及主从模块之间的通讯协议框架。协议框架协议基于二进制协议框架,完成命令发送接收、命令上报、内部组网等功能。协议内容3.1设备内部组网协议(或者MCU透传模式协议)备内部组网协议包括设备配对、连接、心跳机制等,目的是将一个子设备加入到设备组中,并保持连接。3.1.1通讯命令格式采用二进制的通讯协议格式,包格式如下表:同步头HeadOption包长度(变长)加密随机数(Option)源设备类型(Option)源设备编码(Option)CMDKeyCMDIDPayloadCRC(Option)2B1B1~2B1B1B3B1B1BNB2B详细的包格式在后续章节介绍3.1.2配对机制配对机制仅适用于设备内组网模式,MCU透传模式不需要组网协议。进入配对模式由主从设备分别触发,只有在进入配对模式后,才处理相关的配对命令。从设备进入配对模式后定时发送配对请求,直到收到请求回应。主设备收到请求后分配一个设备ID给从设备,标识此ID被占用,并等待采集器的上线通知,一定时间内收到通知之后确认存入设备列表,如果没有上线通知,则认为设备没有配对成功,从子设备中删除。从设备收到配对回应后存储设备ID,并且发送上线通知,收到上线通知后完成配对。配对的过程如下图所示:3.1.3连接机制设备每次上电连接需要发送上线通知以及连接所需要的参数给主设备,如下图所示:3.1.4心跳机制使用对等的心跳机制,主设备和从设备都可以发现对方的异常状态。3.2设备与云端通讯协议设备与云端通讯协议基于MQTT协议,数据包使用MQTT协议传输,数据加密方式采用SSL加密,命令码采用2进制命令格式同设备间通讯协议。3.2.1MQTT通讯框架本协议是针对与设备的数据通信,目前通信节点包括:设备、云端和APP终端三方。WIFI上的协议采用MQTT协议框架,串口上的通信采用包含包头和校验的二进制协议,通信包采用二进制格式传输,高位在前低位在后。此协议定义的MQTTTopic类型有以下2种:单播,unicast/u/{TargetType}/{TargetID}广播,broadcast/b/{SourceType}/{SourceID}注释:TargetType:目标设备类型,TargetID:目标设备编码SourceType:源设备类型,SourceID:源设备编码3.2.2通讯命令格式设备与云端、APP的通讯命令分为4种:请求与回应、通知命令、广播命令,具体的命令以及格式在后面章节介绍。3.2.2连接流程设备连接云端的步骤如下图:3.3数据包格式定义数据包的格式根据通讯双方的不同、数据链路的差异会有不同的包格式,本协议为尽量保证数据包格式的统一,做了几点规划:数据包格式中核心的部分包括CMDID和CMDPayload,这两部分格式所有的包中保持一致,CMDID1个字节,CMDPayload紧跟CMDID长度N字节。设备间通讯,包括内部命令、外部转发命令等的数据包格式虽然可能不一样,但是都可以通过包头中的Option字节进行区分,可以公用相同的解析函数外部串口通讯的命令格式与设备间通讯格式保持一致。设备间通讯数据格式同步头HeadOption包长度(变长)加密随机数(Option)源设备类型(Option)源设备编码(Option)CMDKeyCMDIDPayloadCRC(Option)2B1B1~2B1B1B3B1B1BNB2BFixheader固定帧头,格式如下表:同步头HeadOption包长度(变长)2Byte1Byte1~2Byte同步头:0x5CFEHeadOption:Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0预留预留预留预留CheckSum校验广播类型链路CRC校验加密选项typedefenum{OPTIONAL_ENCRYPT_BIT=(1<<0),OPTIONAL_CRC_BIT=(1<<1),OPTIONAL_BROADCAST_DATALINK_BIT=(1<<2),OPTIONAL_CHECKSUM_BIT=(1<<3),}OptionalBitsT;包长度:长度包括本字节之后的所有数据的长度长度是1~2个字节字节数取值长度范围10x0~0x7F0~12720x0180~0x7FFF128~16383长度的编码方式参考MQTT:如长度是321=(65+2*128),那么会被编码为两个字节,低字节为65+128=193.高字节为2。可变包格式可变包格式需要通过HeadOption来解析,格式如下表:OptionBit0OptionBit2OptionBit1OptionBit3加密随机数设备类型设备编码消息体CRC校验CheckSum1Byte1Byte3Byte2Byte1Byte异或随机数:如HeadOption中的加密选项为0,那么加密随机数这个字节不存在,同时数据不会进行加密源设备信息:用于广播类型的数据链路,需要标识数据的来源。CRC校验:采用16bit的CRC算法,CRC算法参照附录。CheckSum:采用8Bit的和校验,用于对数据长度比较敏感,但是又需要进行数据校验的场景设备编码和设备类型:Payload中可能需要用到的内部设备Type和ID的定义:内部设备Type和设备ID在设备配对时由主设备分配给从设备,其中Type由主设备获取到从设备的DeviceType之后映射一个数值,并分配给从设备,建立映射关系。ID的3字节构成为:Byte3Byte2Byte1随机数,避免不同子网的ID冲突ID序号,由主设备维护命令消息体结构如下表CMDkeyCMDIDPayload1Byte1ByteNByteCMDKey:命令标识,主要作用是标识命令的类型以及编号,由主设备生成,发送给从设备,从设备将key返回给主设备,另外在还标识命令的类型CMDKey描述备注1设备内部消息(组网、透传模式的内部消息)这些命令没有重发机制,不能保障一定到达2Notify类消息3Broadcast类消息4~31预留reserved32~255动态分配的key,用于数据的转发、透传此范围的命令如果没有回复会重发,重发一定次数后丢弃,所以此消息可能会多次到达CMDID:命令码,1个字节命令码描述1配对请求2配对请求回应3设备启动通知4设备启动回应5WiFi就绪通知6WiFi断开通知7云就绪通知8云断开通知9WiFi上电通知10WiFi模块配置完成通知11退出WiFi模块配置12退出WiFi模块配置回应13重新配置WiFi模块14重新配置WiFi模块回应15设置WiFi模块串口波特率16设置WiFi模块串口波特率回应17查询WiFi模块串口波特率18查询WiFi模块串口波特率回应WiFi模块消息起始32设备上线通知33WiFi配置完成通知34获取设备WiFi模块监控信息35获取设备WiFi模块监控信息回应36设置路由器信息37设置路由器信息的回应38删除子设备39删除子设备回应40获取在线设备列表41获取在线设备列表回应42设置设备拥有者43设置设备拥有者回应44设置配对模式45设置配对模式回应46在线设备列表变更通知47~63WiFi模块预留所有设备公共命令起始64主MCUOTA传输文件65主MCUOTA传输文件回应66设置出厂参数67设置出厂参数回应68DebugLog输出控制69DebugLog输出控制回应70DebugLog信息输出71从MCUOTA传输文件72从MCUOTA传输文件回应73云端推送通知信息76OTA完成通知上报77~95设备公共命令预留设备业务命令起始96~127设备自定义设备内部消息128~255设备自定义设备与云端/APP通讯消息Payload:命令数据,N字节5.4实例一个所有Option都打开的包结构如下:同步头HeadOption包长度(变长)加密随机数(Option)源设备类型(Option)源设备编码(Option)CMDKeyCMDIDPayloadCRC(Option)2B1B1~2B1B1B3B1B1BNB2B数据组包实例以下是使用CRC校验,并且加密的数据包的组包过程:假设命令包是1234,4个字节,现在要组包1:CRC第一步计算这4个字节的crc值,假设算出来是5、6第一步CRC之后的数据包就变成了1、2、3、4、5、6,6个字节2:加密加密第一步:加入一个随机数,假设这个随机数是0,现在包就是7个字节了,0、1、2、3、4、5、6加密第二步:异或,将除加密随机数外的其他数据都和加密随机数进行异或,得到得数据应该是0、1、2、3、4、5、6机密第三步:查表加密,假设表中0对应的是6、1对应的是5依次类推,那么查表之后的数据变为了6、5、4、3、2、1、0加密结束,payload最终就是6、5、4、3、2、1、0了3:加入包头Payload是7个字节,optional是CRC和加密,那么包头为FE5C0307最终包数据为:FE5C030706050403020100解包的过程与组包相反3.3.2设备与云、APP通讯数据格式命令数据格式:源设备类型源设备IDCMDID5Byte12Byte1ByteNBytePad串口通讯数据格式下行数据格式,PAD->设备同步头HeadOption包长度(变长)加密随机数(Option)源设备类型(Option)源设备编码(Option)源设备GUID目标设备GUIDCMDIDPayloadCRC(Option)2B1B1~2B1B1B3B34字节1BNB2B上行数据格式,设备->PAD同步头HeadOption包长度(变长)加密随机数(Option)源设备类型(Option)源设备编码(Option)源设备GUIDCMDIDPayloadCRC(Option)2B1B1~2B1B1B3B34字节1BNB2B公共命令定义下表是公共命令码以及命令数据的定义,此表仅涉及到上文提到的CMDID和命令信息码(或回复码),命令中的其他部分数据请参考上文中的数据包定义。命令码命令描述通信方命令组成备注设备内部命令起始1请求配对从设备->主设备CMDKey[1Byte],0x01CMDID[1Byte]业务设备类型[5Byte]当前的内部设备类型[1Byte]当前的内部设备编码[3Byte],全0表示未配置过,非全0表示之前配置过设备业务编码长度[1Byte]设备业务编码[NByte]5个字节的业务设备类型,需要向乐君申请,并且保存在从设备中设备业务编码是用从设备自行定义的设备ID字符串,不超过32字节2请求配对回应主设备->从设备CMDKey,0x01CMDID[1Byte]RC[1Byte],参考RC表分配的设备类型[1Byte]分配的设备ID[3Byte]3设备启动通知MCU/从设备->主设备CMDKey[1Byte],0x01CMDID[1Byte]版本号[1Byte]子设备类型[1Byte],参考5.3章节:子设备类型表业务设备类型[5Byte]内部设备类型[1Byte]内部设备编码[3Byte]设备业务编码长度[1Byte]设备业务编码[NByte]4设备启动通知的回应主设备->MCU/从设备CMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],参考RC表5WiFi就绪通知主设备->MCU/从设备CMDKey[1Byte],0x01CMDID[1Byte]6WiFi断开通知主设备->MCU/从设备CMDKey[1Byte],0x01CMDID[1Byte]7云就绪通知主设备->MCU/从设备CMDKey[1Byte],0x01CMDID[1Byte]8云断开通知主设备->MCU/从设备CMDKey[1Byte],0x01CMDID[1Byte]9WiFi模块上电通知WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]WiFi模块上电后定时发送上电通知给MCU,直至MCU上报上线通知给WiFi模块(适用于用于透传模式)10WiFi模块配置完成通知WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],0成功,3超时,4退出11退出WiFi模块配置MCU->WiFi模块CMDKey[1Byte],0x01CMDID[1Byte]12退出WiFi模块配置回应WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],0成功,1失败13重新配置WiFi模块MCU->WiFi模块CMDKey[1Byte],0x01CMDID[1Byte]14重新配置WiFi模块回应WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],0成功,1失败15设置WiFi模块串口波特率MCU->WiFi模块CMDKey[1Byte],0x01CMDID[1Byte]Baudrate[4Byte]Baudrate取值:9600192003840057600115200其他值返回fail默认值是960016设置WiFi模块串口波特率回应WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],0成功,1失败返回值以新设置的波特率发送17查询WiFi模块串口波特率MCU->WiFi模块CMDKey[1Byte],0x01CMDID[1Byte]18查询WiFi模块串口波特率回应WiFi模块->MCUCMDKey[1Byte],0x01CMDID[1Byte]RC[1Byte],0成功,1失败Baudrate[4Byte]WiFi模块命令起始32设备信息上报WiFi模块->Cloud/APPCMDID[1Byte]Num[1Byte],设备个数设备拥有者的小智ID[string,10字节]WiFi模块Mac地址[ASCII,12字节]GUID[ASCII,17字节]、设备业务编码长度[1Byte]、设备业务编码[NByte]、固件版本[1BYTE]、设备硬件架构类型[1BYTE]、设置是否在线[1Byte],若干MQTT主题:/b/{SourceType}/{SourceID}第一个设备是主设备设备硬件架构类型参考“设备硬件架构类型编码表”设备是否在线,0不在线,1在线33WiFi配置完成通知WiFi模块->APPCMDID[1Byte]设备GUID[ASCII,17字节]用户的小智ID[string,10字节]设备业务编码长度[1Byte]设备业务编码[NByte]MQTT主题:/u/{TargetType}/{TargetID}34获取WiFi模块监控数据Cloud/APP->WiFi模块CMDID[1Byte]35获取WiFi模块监控数据回应WiFi模块->Cloud/APPCMDID[1Byte]WiFi模块连接信号强度[1Byte],有符号的1个字节,一般范围在-100Dbm~0DbmWiFi模块型号[16byte],小于16字节的字符串36设置WiFi配置信息APP/Cloud/串口控制端->设备CMDID[1Byte]是否设置拥有者ID[1Byte],0不设置,1设置设备拥有者的小智ID[string,10字节]是否设置路由器信息[1Byte],0不设置,1设置SSIDLen,用户名长度[1BYTE],用户名长度小于等于32字节PWDLen,密码长度[1BYTE],密码小于等于64字节SSIDPWD37设置WiFi配置信息回应设备->APP/Cloud/串口控制端CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败38删除子设备APP/Cloud/串口控制端->设备CMDID[1Byte]GUID[ASCII,17字节]39删除子设备回应设备->APP/Cloud/串口控制端CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败40获取设备列表APP/Cloud/串口控制端->主设备CMDID[1Byte]41获取设备列表回应主设备->APP/Cloud/串口控制端CMDID[1Byte]Num[1Byte],设备个数设备拥有者的小智ID[string,10字节]WiFi模块Mac地址[ASCII,12字节]GUID[ASCII,17字节]、设备业务编码长度[1Byte]、设备业务编码[NByte]、固件版本[1BYTE]、设备硬件架构类型[1BYTE]、设置是否在线[1Byte],若干设备是否在线,0不在线,1在线44设置设备进入配对模式App/Cloud/串口控制端->设备CMDID[1Byte]45设置设备进入配对模式回应设备->App/Cloud/串口控制端CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败)[BYTE]47设置设备退出配对模式App/Cloud/串口控制端->设备CMDID[1Byte]48设置设备退出配对模式回应设备->App/Cloud/串口控制端CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败)[BYTE]

49请求同步时间设备->CloudCMDID[1Byte]50请求同步时间回应Cloud->设备CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败)[BYTE]RTC时间[67Byte],格式是{秒-分-时-日-月-年-星期几},各一个字节星期几的范围从1~7,1表示星期一51扫描AP列表控制端->设备CMDID[1Byte]52扫描AP列表回应设备到控制端CMDID[1Byte]RC(参考命令回应编码表:0成功,1失败)[BYTE]APNumber[1Byte],扫描到的AP数量AP信息{[32Byte],SSID[1Byte],RSSI信号强度}若干SSID为字符串,最大32字节,返回数据中固定32字节位置存放SSID。信号强度取值范围0~100所有设备公共命令起始64主MCUOTA传输文件Cloud->设备CMDID[1Byte]总包数[2Byte]当前包号[2Byte]包内容[NBYTE,最大长度1024]65主MCUOTA传输文件回应设备->CloudCMDID[1Byte]RC(参考命令回应编码表:0成功,1失败,32包号错误,33数据校验错误)[1BYTE]当前包号[2Byte]66设置出厂信息App/Cloud->设备CMDID[1Byte]设备ID[12Byte]设备业务ID长度[1Byte]设备业务ID[NByte]设备业务ID长度为0表示不需要设备业务ID暂时只需要工厂测试程序支持67设置出厂信息回应设备->App/CloudCMDID[1Byte]RC(参考命令回应编码表:0成功,1失败68DebugLog输出控制App/Cloud->设备CMDID[1Byte]DebugLog开关[1Byte],0关,1开是否掉电保存[1Byte],0掉电不保存,1掉电保存暂时云端实现69DebugLog输出控制回应设备->App/CloudCMDID[1Byte]RC(参考命令回应编码表:0成功,1失败70DebugLog信息输出设备->App/CloudCMDID[1Byte]固件版本version[1Byte]日志类型LogType[1Byte]Log内容[NByte],字符串71从MCUOTA传输文件Cloud->设备CMDID[1Byte]总包数[2Byte]当前包号[2Byte]包内容[NBYTE,最大长度1024]用于升级主从MCU架构下的从MUC固件72从MCUOTA传输文件回应设备->CloudCMDID[1Byte]RC(参考命令回应编码表:0成功,1失败,32包号错误,33数据校验错误)[1BYTE]当前包号[2Byte]73云端推送通知信息Cloud->APP/设备CMDID[1Byte]推送信息内容[nByte]76OTA升级完成上报设备->Cloud/APPCMDID[1Byte]RC[1Byte],0成功,1失败云端以这个命令作为OTA真正完成的判断标准编码表5.1节点类型编码表节点类型编码类型名称5.2命令回应编码表0~31,公共错误码命令回应编码命令回应含义0成功1失败内部通讯公共RC值起始2配对失败,设备满3WiFi配置(Easylink)超时4WiFi配置(Easylink)退出5~31内部通讯公共RC值预留外部通讯公共RC值起始32OTA包号错误33OTA数据校验错误34当前状态不允许OTA35~63外部通讯公共RC值预留业务RC值起始64~255业务错误码5.3子设备类型表子设备类型描述1透传模式下的MCU设备2组网模式下的从设备5.4设备硬件架构类型编码表设备硬件结构类型描述0单MCU架构1双MCU架构(WiFi模块+控制MCU模块)附录6.1CRC校验算法staticconstuint8c_crc_htalbe[]=//CRC高8位查表{0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0x

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论