题型:问答 和 写程序(写 状态机程序、写报文结构程序)
方向:
1、操作命令,应该是实验用过的,以及一些讲过的概念(很少)
2、程序理解,主要是实验 的前面几个,特简单的。包括 补充的 sizeof 那个程序,
注意:每个语句、每个标识符都看懂,少一个都不行,实验的程序前几个 简单,看懂意思、语法、改错
3、状态机设计、编程。比如识别 字串的 NNNN,识别 字串的78
4、学会报文定义,用C语言定义。比如IP报文 UDP 报文。当然不可能题目就是IP、UDP,和 MAVLINK 有关
5、通信软件相关的概念问答,当然比 1 的简单回答要深刻
6、报文C语言定义、封装报文的C语言程序,解析报文的C语言程序
0、常用命令
gcc编译+运行
1 2 3 4 5 6 7 8 9 10 11 12 gcc -c ../serial/lflserial.c gcc -o tty_r tty_recv_file.c lflserial.o gcc -o tty_s tty_send_file.c lflserial.o ./tty_r /dev/pts/4 tt ./tty_s /dev/pts/3 test_file diff test_file tt
其他命令
1 2 3 4 5 6 7 8 9 10 11 12 13 cd path pwd cp [options] 源文件 目标文件(夹) mv [options] 源文件 目标文件 gcc c源文件 [-o 可执行文件名] rm [option] 文件(夹)名 diff [options] file1 file2 ls chmod 777 文件名 chgrp 组名 文件名/目录 chown [-R] 账号名:组群 文件/目录 vim 文件名 gedit filename
Linux文件夹
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 /bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示 /lib 标准程序设计库,又叫动态链接共享库,作用类似windows里的.dll文件 /sbin 系统管理命令,这里存放的是系统管理员使用的管理程序 /tmp 公用的临时文件存储点 /root 系统管理员的主目录 /mnt 系统提供这个目录是让用户临时挂载其他的文件系统。 /lost+found 这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下叫什么.chk)就在这里 /proc 虚拟的目录,是系统内存的映射。可直接访问这个目录来获取系统信息。 /opt 存放可选程序的目录,比如我想安装firefox的最新beta版,可以放在这里。卸载的话删除那个文件夹好了 /var 某些大文件的溢出区,比方说各种服务的日志文件 /usr 最庞大的目录,要用到的应用程序和文件几乎都在这个目录。其中包含: /usr/x11r6 存放x window的目录 /usr/bin 众多的应用程序 /usr/sbin 超级用户的一些管理程序 /usr/doc linux文档 /usr/include linux下开发和编译应用程序所需要的头文件 /usr/lib 常用的动态链接库和软件包的配置文件 /usr/man 帮助文档 /usr/src 源代码,linux内核的源代码就放在/usr/src/linux里 /usr/local/bin 本地增加的命令 /usr/local/lib 本地增加的库
一、概念题
0.C语言基础
标识符
sizeof 获取某个数据类型所占用空间的字节数
typedef 为一种数据类型定义一个新名字
struct 定义结构体
union 定义共用体
联合体:所有成员共用一块地址空间 ,也就是说联合体只放了一个被选中的成员;
结构体:所有的成员的内存 占用是累加的,其所有成员都存在,不同成员会放在不同地址;
1.通信
通信 (Communication)就是信息的传递 ,是指由一地向另一地进行信息的传输与交换,其目的是传输消息。
把A地的信息在B地近似重现、把A地的信息传输到B地、靠协议实现的传输
2.信息
指 音讯 、消息 、通讯系统传输和处理的对象 ,泛指人类社会 传播 的一切 内容。
3.硬件
是 计算机硬件 的简称,是指 计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称 。这些物理装置按 系统结构 的要求构成一个有机整体为 计算机软件 运行提供物质基础。简而言之,硬件的功能是输入并存储 程序 和数据,以及 执行程序 把 数据 加工成可以利用的形式。从外观上来看,微机由 主机 箱和 外部设备 组成。
4.操作系统
操作系统(operating system,简称OS)是管理计算机硬件 与软件 资源的计算机程序 。操作系统需要处理如管理与配置 内存 、决定系统资源 供需的优先次序、控制输入设备 与输出设备 、操作网络与管理文件系统 等基本事务。操作系统也提供一个让用户与系统交互 操作的界面。
5.软件
包括程序 、数据 及其相关文档 的完整集合
13.通信软件
是指实现通信协议的软件
完成数据/信息传输与交换的软件
完成数据/信息产生与应用的软件
实现网络中的管理/计费的软件
特征:
线程设计:多终端通信
协议体系:协议栈与报文传递
通信协议:状态机与协议
报文协议:协议解析与处理
字节与报文协议:数据接收与报文识别
操作系统内核:需要硬件驱动程序的支持
计算机的IO接口:需要通信硬件的支持
6.应用软件
应用软件(Application)是和系统软件相对应的,是用户可以使用的各种程序设计语言 ,以及用各种程序设计语言编制的应用程序的集合,分为应用软件包 和用户程序 。应用软件包 是利用计算机解决某类问题而设计的程序的集合,多供用户使用。
应用软件是为满足用户不同领域、不同问题的应用需求而提供的那部分软件。 它可以拓宽计算机系统的应用领域,放大硬件的功能。
7.APP
指智能手机的第三方应用程序 。
主要指的都是ios mac android等系统下的应用软件。
8.编程语言
编程语言(programming language)可以简单的理解为一种计算机和人都能识别的语言。一种计算机语言让程序员能够准确地定义计算机所需要使用的数据,并精确地定义在不同情况下所应当采取的行动。
计算机编程语言主要包括汇编语言、机器语言以及高级语言
9.编辑
10.编译
编译就是把高级语言变成计算机可以识别的2进制语言 ,计算机只认识1和0,编译程序 把人们熟悉的语言换成2进制的;将源代码一次性转换成目标代码的过程。
1、利用编译程序 从源语言编写的源程序 产生目标程序 的过程。
2、用编译程序 产生目标程序 的动作
11.脚本
使用一种特定的描述性 语言 ,依据一定的 格式 编写的 可执行文件
12.解释执行
编译:将源代码一次性转换成目标代码的过程
解释:将源代码逐条转换成目标代码同时逐条运行的过程。
执行解释过程的程序叫做解释器
14.命令
计算机命令:指计算机的快捷指令
15.指令
指令是控制计算机执行的命令 ,它由操作码和地址码组成。
指令是计算机能实现的基本操作,是指挥机器工作的指示和命令 ,指令均为二进制数形式;指令由操作码和地址码组成,操作码告诉计算机执行什么操作,地址码告诉计算机到哪个存储单元地址中读取参与操作的数据。
16.程序
程序是一组计算机能识别和执行的指令 ,是若干指令或命令的集合,运行于电子计算机上,满足人们某种需求的信息化工具。
17.通信程序
利用通信协议编写的具有通信功能的程序
18.数据
程序 文件中包含的 变量初值 和程序使用的 字面常量值 。
19.数据结构
相互之间存在一种或多种特定关系的数据元素的集合
20.缓冲区(缓存)
内存空间的一部分 。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
21.变量
没有固定的值,可以改变的数;在程序运行时其值可以改变的量
22.函数
函数是指一段可以直接被另一段程序或代码引用的程序或代码 。 也叫做子程序、(OOP中)方法。
23.子程序
是一个大型程序中的某部份代码,由一个或多个语句块组成 。 它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
所有的高级语言中都有子程序这个概念,用子程序实现模块的功能。 在 C语言 中,子程序是由一个主函数和若干个函数构成的
24.队列
队列是一种特殊的线性表 ,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
25.进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动 ,是系统进行资源分配和调度的基本单位,是 操作系统 结构的基础。
进程是线程的容器。 程序是指令、数据及其组织形式的描述,进程是程序的实体。
一个程序就是一个进程,每个进程至少1个线程
26.线程
线程在程序中是独立的、并发的执行流。
进程仅负责为各个线程提供所需的资源,真正执行任务的是线程,而不是进程。
27.通信线程
27.并行和并发
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
28.阻塞/非阻塞
阻塞 和非阻塞 指的是调用者(程序 )在等待返回结果(或输入)时的状态。
阻塞时,在调用结果返回前,当前线程会被挂起 ,并在得到结果之后返回。
非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。
补充:同步与异步
同步和异步 关注的是消息通信机制 (synchronous communication/ asynchronous communication)。
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。
而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果 。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
29.文件
文件是计算机文件属于文件的一种 ,与普通文件载体不同,计算机文件是以计算机硬盘为载体存储在计算机上的信息集合。 文件可以是文本文档、图片、程序等等。 文件通常具有三个字母的文件扩展名,用于指示文件类型
30.设备文件
设备文件是应用程序与驱动程序交互的接口
31.硬件接口
硬件接口(hardware interface)指的是两个硬件设备之间的连接方式 。硬件接口既包括物理上的接口,还包括逻辑上的数据传送协议。
32.通信线路
通信线路是保证信息传递的通路。
目前长途干线中有线主要是用大芯数的光缆,另有卫星、微波等无线线路。 省际及省内长途也是以光缆为主,另有微波、卫星电路。
33.通信硬件接口
是指中央处理器和标准通信子系统之间的接口。
34.路由
路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程 [1] 。路由工作在OSI参考模型 第三层——网络层 的数据包 转发设备。
路由是指路由器 从一个接口上收到数据包 ,根据数据包的目的地址 进行定向并转发到另一个接口的过程。路由通常与桥接来对比,在粗心的人看来,它们似乎完成的是同样的事。它们的主要区别 在于桥接 发生在OSI参考模型 的第二层(数据链路层 ),而路由发生在第三层(网络层 )。
35.路由表
路由器又可以称之为网关设备。路由器(Router)是连接两个或多个网络的硬件 设备,在网络间起网关 的作用,是读取每一个数据包中的地址然后决定如何传送的专用智能性的网络设备。它能够理解不同的协议,例如某个局域网使用的以太网协议 ,因特网使用的TCP/IP协议 。
二、状态机
通过状态来决定某个任务是否进行,称为状态机程序设计。即 发生了某件事,要做什么 还得根据状态来决定。
下雨事件
状态 :在室内、在室外
事件 :雨停了、下雨了
动作 :打球、出门、看书、打伞、回家
状态转移 :相应的事件和状态下发生了状态的改变
掌握三点
事件/状态/转移
例,有一个文本文件需要传输,但接收方不知道文件长度。这是用你的学号后2位作为文件结束,请设计一个识别文件结束的状态机。比如学号是35
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 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 #include <stdio.h> #define M 4 #define N 3 #define S1 0 #define S2 1 #define S3 2 #define EVENT_3 0 #define EVENT_5 1 #define EVENT_NOT3 2 #define EVENT_NOT3NOT5 3 int save (char num) ; int logerror (char num) ; int getEvent (int event, char cc, int currentState) ; typedef struct matrix { int (*Action)(char num); int nextState; } matrix_t ; matrix_t Set[M][N] = { {{save, S2}, {save, S2}}, {{logerror, S1}, {save, S3}}, {{save, S1}, {logerror, S2}}, {{logerror, S1}, {save, S1}}, }; int save (char num) { printf ("here is save num : %c!\n" , num); return 0 ; } int logerror (char num) { printf ("logerror\n" ); } int getEvent (int event, char cc, int currentState) { if (cc == '3' ) event = EVENT_3; else if (cc == '5' ) event = EVENT_5; else if (cc != '3' && currentState == S1) event = EVENT_NOT3; else if (cc != '3' && cc != '5' && currentState == S2) event = EVENT_NOT3NOT5; return event; } int main (int argc, char *argv[]) { int currentState = 0 ; int EVENT = -1 ; char cc = '3' ; int i = 5 ; while (i--){ cc = '3' ; EVENT = getEvent(EVENT, cc, currentState); printf ("Now state is %d, event is %d, " , currentState+1 , EVENT+1 ); Set[EVENT][currentState].Action(cc); currentState=Set[EVENT][currentState].nextState; cc = '5' ; EVENT = getEvent(EVENT, cc, currentState); printf ("Now state is %d, event is %d, " , currentState+1 , EVENT+1 ); Set[EVENT][currentState].Action(cc); currentState=Set[EVENT][currentState].nextState; if (currentState == S3){ printf ("File received!" ); break ; } } }
三、MAVLINK
考报文的定义和封装
作用
MAVlink是无人机地面站和无人机之间的通信协议
心跳:飞机和地面通信的通信通路测试
飞机状态:各个部件的状态、位置
飞行任务:导航、路线等
控制命令:返航、作业执行
实时视频:视频数据
作业控制:农药播撒等
报文的定义和封装
类型定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #define MAVLINK_MAX_PACKET_LEN (MAVLINK_MAX_PAYLOAD_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES) #define MAVLINK_NUM_NON_PAYLOAD_BYTES (MAVLINK_NUM_HEADER_BYTES + MAVLINK_NUM_CHECKSUM_BYTES ) #define MAVLINK_NUM_HEADER_BYTES (1 + MAVLINK_CORE_HEADER_LEN) #define MAVLINK_CORE_HEADER_LEN 5 #define MAVLINK_NUM_CHECKSUM_BYTES 2 #define MAVLINK_MAX_PAYLOAD_LEN 255 typedef struct __mavlink_message { uint16_t checksum; uint8_t magic; uint8_t len; uint8_t seq; uint8_t sysid; uint8_t compid; uint8_t msgid; uint64_t payload64[(MAVLINK_MAX_PAYLOAD_LEN + 9 ) / 8 ]; } mavlink_message_t
心跳信息
心跳信息是mavlink消息的载荷数据 ,放在 Payload(~255) 中,占9个字节
报文类型:
1 2 3 4 5 6 7 8 typedef struct __mavlink_heartbeat_t { uint32_t custom_mode; uint8_t type; uint8_t autopilot; uint8_t base_mode uint8_t system_status; uint8_t mavlink_version; } mavlink_heartbeat_t
定义变量
类型
变量
消息类型 mavlink_message_t
消息变量定义 mavlink_message_t msg;
心跳类型 mavlink_heartbeat_t
心跳变量定义 mavlink_heartbeat_t heartbeat;
四、实验
实验1 LINUX串口通信程序设计 (第二讲)
LINUX串口设备通信接口程序,字串的接收、存储和转发
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 43 44 45 46 47 48 49 50 51 52 int serRev (int fd,char *buff,int len) { if (fd>0 ) { return (read(fd,buff,len)); }else { return (0 ); } } int serSend (int fd,char *buff,int len) { if (fd>0 ) { return (write(fd,buff,len)); }else { return (0 ); } } int serOpenCOM (char *DEV,int Speed,int DataBits,int StopBits,int Parity) { int fd; fd = serOpenDev(DEV); if (fd>0 ) { if (serSetSpeed(fd,Speed)) { if (serSetParity(fd,DataBits,StopBits,Parity)) return (fd); return (0 ); } else return (0 ); } else return (0 ); } int serCloseCOM (int fd) { return (serCloseDev(fd)); }
发送
1 2 3 4 5 6 7 while (1 ) { s_len = read(fd, buff, 1024 ); if (s_len <= 0 ) break ; serSend(tty_fd, buff, s_len); }
接收
1 2 3 4 5 6 7 8 char r_buffer[1024 ];bzero(r_buffer, sizeof r_buffer); while (1 ) { r_len = serRev(r_fd, r_buffer, sizeof r_buffer); write(rd, r_buffer, r_len); }
实验2 报文封装与解析程序设计
设计一个报文格式,定义报文类型,封装一个报文,识别报文以及解析其内容
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 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 #include <stdio.h> typedef unsigned char u_int8_t ; typedef unsigned short u_short; typedef unsigned int u_int32_t ; struct ip_addr { u_int32_t IP_addr; }; struct in6_addr { union { u_int8_t Byte[16 ]; u_short Word[8 ]; } u; }; struct packet_t { u_int8_t Ver:4 ; u_int8_t Com:4 ; u_int8_t ComArg; u_short PacketDataLength; struct ip_addr IPv4Address ; }; typedef struct _PacketHdr_t { u_int32_t Ver:4 ; u_int32_t Class:8 ; u_int32_t FlowLabel:20 ; u_short PayloadLength; u_short Reverse; struct in6_addr IPv6Address ; } PacketHdr_t; struct ip_hdr { unsigned short int IP_v:4 ; unsigned short int IP_hl:4 ; u_int8_t IP_tos; u_short IP_len; u_short IP_id; u_short IP_off; u_int8_t IP_ttl; u_int8_t IP_p; u_short IP_sum; struct ip_addr IP_src , IP_dst ; }; struct ip_hdr_c { u_int8_t IP_v:4 ; u_int8_t IP_hl:4 ; u_int8_t IP_tos; u_short IP_len; u_short IP_id; u_short IP_off; u_int8_t IP_ttl; u_int8_t IP_p; u_short IP_sum; struct ip_addr IP_src , IP_dst ; }; struct ip_hdr_l { unsigned long IP_v:4 ; unsigned long IP_hl:4 ; u_int8_t IP_tos; u_short IP_len; u_short IP_id; u_short IP_off; u_int8_t IP_ttl; u_int8_t IP_p; u_short IP_sum; struct ip_addr IP_src , IP_dst ; }; main() { PacketHdr_t Packet6; struct packet_t Packet4 ; struct ip_hdr IP_Head ; struct ip_hdr_c IP_Head_c ; struct ip_hdr_l IP_Head_l ; printf ("\n" ); printf ("\nsizeof struct ip_addr = %d\n" , sizeof (struct ip_addr)); printf ("\nsizeof PacketHdr_t = %d\n" , sizeof Packet6); printf ("\nsizeof packet_t = %d\n" , sizeof Packet4); printf ("\nsizeof IP_Head_t = %d\n" , sizeof IP_Head); printf ("\nsizeof IP_Head_t_c = %d\n" , sizeof IP_Head_c); printf ("\nsizeof IP_Head_t_l = %d\n" , sizeof IP_Head_l); }
实验3 简单的PPP程序设计 (第三讲)
长度帧与PPP帧设计与定义,报文接收 与识别 、转发(设计队列与路由表)
1.长度帧 length-frame
帧格式:
帧定义 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 typedef struct frame_head { char cFlag[2 ]; short shortLength; } t_frame_head; typedef struct frame { t_frame_head frameHead; char frameData[0 ]; } t_frame; #define MAX_DATA_LENGTH 1500 #define MAX_FRAME_LENGTH (sizeof (t_frame_head *) + MAX_DATA_LENGTH) void length_framePack (t_frame *framePoint, char *dataP, int dataLength) ;void length_frameUnpack (t_frame *framePoint, char *dataP, int *data_lengthP) ;void length_frameRecognition (int fd, t_frame *framePoint) ;
报文收发 主逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 while (1 ) { s_len = read(fd, buff, N); if (s_len <= 0 ) break ; length_framePack((t_frame *)&frame[0 ], buff, s_len); serSend(tty_fd, frame, s_len + sizeof (t_frame_head)); } while (1 ) { length_frameRecognition(tty_fd, (t_frame *)&frame[0 ]); length_frameUnpack((t_frame *)&frame[0 ], buff, &s_len); if (s_len <= 0 ) break ; write(fd, buff, s_len); }
报文识别 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void length_frameRecognition (int fd, t_frame *framePoint) { char cc[2 ], tc; short len; again: cc[0 ] = 0 ; cc[1 ] = 0 ; while (cc[0 ] != 0x7e || cc[1 ] != 0x7e ) readFromUART(fd, &cc[0 ], 2 ); readFromUART(fd, (char *)&len, 2 ); if (len > MAX_DATA_LENGTH) goto again; readFromUART(fd, framePoint->frameData, len); framePoint->frameHead.cFlag[0 ] = 0x7e ; framePoint->frameHead.cFlag[1 ] = 0x7e ; framePoint->frameHead.shortLength = len; }
帧封装与解封 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void length_framePack (t_frame *framePoint, char *dataP, int dataLength) { framePoint->frameHead.cFlag[0 ] = 0x7e ; framePoint->frameHead.cFlag[1 ] = 0x7e ; framePoint->frameHead.shortLength = dataLength; memcpy (framePoint->frameData, dataP, dataLength); } void length_frameUnpack (t_frame *framePoint, char *dataP, int *data_lengthP) { register int l; l = framePoint->frameHead.shortLength; memcpy (dataP, framePoint->frameData, l); *data_lengthP = l; }
问题:从串口读多少个帧才知道是一个文件结束 ?
可以有三个方法:
1)数据的最后增加0000或NNNN等特殊数值;
例:r_fd = serOpenCOM(argv[1], 115200, 8, 1, 'N');
,其中字符“N”为Parity(校验位)。
2)在发整个数据前先发数据整个文件数据长度;
3)增加一个特殊帧,比如长度为0的帧。
如 len == 0 则结束 ->
封装长度为0的帧 ->
把帧frame送到串口文件 ->
结束
Tips:
Please indicate the source and original author when reprinting or quoting this article.