1、3. 接收server传输的数据4. 显示数据。3 服务器设计(linux)1. 用于接收(app)客户端发送的命令2. 处理命令3. 转发给硬件4. 读取硬件传输数据5. 把数据传回(app)客户端1.4 硬件设计1.Led灯点亮灯:led1、led2。2.温度传感器把温度数据读取到客户端。 3蜂鸣器用于报警以及音乐播放.第二章 详细设计2。1 代码调用过程代码调用过程如图所示:图2-1 代码调用图分析代码调用过程:0. 准备工作:1.先调用insmodled。ko插入模块2.register_chrdev注册字符设备驱动1.App:fd = open(/dev/led”,O_RDONLY)
2、;2. drivers:2. sys_open(”/dev/led,O_RDONLY) 3.由内核为我们匹配,看是否能够找到设备号为249的led-drivers 4。如果匹配成功,继续找到structfile_operationsled_fops结构体 5.通过结构体找到 open函数的入口led_fops.open 6。led_open 7.arm_init 2 文件IO (系统库函数)1.Open 打开文件返回一个文件描述符2.Read 通过文件描述符fd,读取文件3.Write 通过文件描述符fd,写文件4.Close (进程结束的时候,会自动关闭,可以不必显示的调用close)阻塞:
3、poll机制解决客户端如果要接收服务器回发的数据,则需要读取网络套接字,此时,客户端涉及到读终端和读服务器,而读终端和读服务器都是会阻塞的,所以调用poll机制解决.int poll(structpollfd fds, nfds_tnfds, int timeout);功能:把所关心的文件描述符加入到structpollfd结构中,告诉内核我要非阻塞的读这个文件描述符,内核为我们判断,如果不阻塞,则相应的状态,参数1 :structpollfd intfd; /所关心的文件描述符 */ short events; /* 告诉内核我要做什么:POLLIN:非阻塞的读*/ short revent
4、s; /*内核返回的状态 */;参数2:关心的描述符的个数参数3:愿意等待多长时间 -1 : 一直等待 0 : 表示愿意等待的时间返回值: 大于0 :表示至少有一个已经成功返回 = 0 : 表示超时 0 : 表示失败2.3 网络编程TCP(即传输控制协议):是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)。适用情况:1适合于对传输质量要求较高,以及传输大量数据的通信。2在需要可靠数据传输的场合,通常使用TCP协议3MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议项目需求:1.Linux平台下a)服务器(serv
5、er)i.等待连接客户端ii.接收客户端发送的数据字符串和文件iii.处理客户端发送的数据和命令iv.发送处理结果给客户端b)客户端i.简单的界面ii.从键盘接收用户输入命令iii.发送数据或者命令给服务器iv.接收服务器返回的结果c)协议:tcp2.实现编程a)TCP四次握手协议b)TCP编程模型图22 TCP编程模型图3.网络编程所需要的API函数a)服务器i.Socketii.Bindiii.Listeniv.Acceptv.Read/readvi.Closeii.Connectiii.Read/readiv.Close通用地址结构structsockaddr u_shortsa_fam
6、ily; / 地址族, AF_xxxchar sa_data14; / 14字节协议地址 ;Internet协议地址结构structsockaddr_in sa_family_tsin_family; /地址族: AF_INET /in_port_tsin_port; /端口号*/structin_addrsin_addr; /* IPV4地址internet address */; /* IPv4地址结构/structin_addr uint32_t s_addr; / address in network byte order / ;2.4 内核驱动开发:(模块编程)1.模块入口moude
7、_init2.模块出口module_exit3.语法 : c语言4.编译(Makefile)a)make installb)makec)cpled。ko /opt/filesystem/test5.执行: 驱动模块后缀:led。ko a) 插入内核: insmodled.ko b) 查看模块:lsmod c) 移除模块:rmmod led2.5 注册字符设备驱动static inline intregister_chrdev(unsigned int major, const char name, conststructfile_operations *fops)把设备注册,添加到字符设备的表
8、格中图23 字符设备驱动图insmodled。ko调用内核驱动模块注册设备到内核字符设备管理注册表中图24 打开文件设备过程图6 操作硬件的过程:(裸奔代码)1.找到外设(led),分析外设功能a)原厂提供b)Google ,baidu2.led原理图图25 led点灯流程图操作led的GPIO控制器,主要有以下两个:GPC0CON : 用于控制GPIO引脚输入还是输出GPC0CON32 LED1 -GPC0CON3 - 15-12 0001 = Output LED2 -GPC0CON4 1916 - 0001 = OutputGPC0DAT : 用于设置电平的高低 GPC0DAT3 -GP
9、C0CON15-12 led1 亮 -高电平1 GPC0DAT4 -GPC0CON1916 led2 -灭 低电平 0Led:GPC0CON寄存器地址0xE0200060#define GPC0CON (*(volitale unsigned long *)0xE0200060)GPC0DAT 寄存器地址0xE0200064define GPC0DAT (*(volitale unsigned long *)0xE0200064)MMU当开启了MMU之后,我们是不能直接访问到物理地址的。需要通过ioreamp把物理地址映射为虚拟地址,我们只能通过虚拟地址操作硬件Virt = ioremap(p
10、hy);intstrncasecmp(const char *s1, const char *s2, size_t n);比较字符s1和s2的前n个字符是否相等,如果相等,则返回05. 裸奔代码操作硬件过程图2-6 操作硬件流程图第三章 测试过程3。1 测试1用户登录输入用户名和密码进行校验2登录成功进入到用户操作界面(如图3-1所示)输入要控制硬件的命令:如:打开led1,则输入on1关闭led1,则输入off1打开音乐播放器,则输入song获取温度,则输入get退出,则输入quit图31 用户操作界面第四章 项目拓展4.1 项目拓展目前本项目实现了通过客户端操作硬件,实现了点亮灯/蜂鸣器报
11、警/音乐播放/温度数据采集功能。除用于温度监测外,在系统中的ARM外围可接入控制电路、其他性能的传感器甚至摄像头等,还可以实现多种其他特殊需要的远程监测及控制,如水位监测、视频监控等,具有十分广阔的应用背景。智能硬件框架(如图4-1所示)图4-1 智能硬件框架图附录服务器模块:/*1.调用socket函数创建套接字。 TCP协议:SOCK_STREAM/ sockfd = socket(AF_INET,SOCK_STREAM,0); if(-1 = sockfd) perror(”socket”); return 1; /填充服务器信息/ struct sockaddr_in servaddr
12、; memset(&servaddr,0,sizeof(servaddr); servaddr.sin_family = AF_INET; /PF_INET servaddr.sin_port = htons(PORT); /端口号(500165536) servaddr.sin_addr.s_addr = inet_addr(SERVERIP); /ip地址 socklen_t adrlen = sizeof(servaddr); /2.调用bind指定本地地址和端口。*/ ret = bind(sockfd,(struct sockaddr *)&servaddr,adrlen); if(
13、-1 = ret) perror(bind”); return -1; /3.调用listen启动监听。 ret = listen(sockfd,1000); if(1 = ret)listen); return 1; printf(server init.d success.。n”); int newfd; char bufBUFSZ = 0; pthread_t tid; while(1) /4.调用accept从已连接列队中提取客户连接。 newfd = accept(sockfd,NULL,NULL); if(newfd = 0) continue; printf(%d connect
14、 success.。n”,newfd); /*为每个客户创建线程去维护它 = tid : 用于存放新建线程ID = do_work : 新建线程从这里开始执行 newfd : 传给执行函数的参数*/ ret = pthread_create(tid,NULL,do_work,&newfd); if(0 != ret) continue; /*设置为可分离态*/ pthread_detach(tid); /*6。调用close关闭连接./ close(sockfd); close(newfd); return 0;/执行函数 (void *表示可以接收任意类型)*/void *do_work(v
15、oid arg) int ret; char bufBUFSZ; int newfd = *(int )arg; char strerr = ”密码或者用户名输入有误!”; unsigned int cmd = 1; unsigned long val = -1; int i = 0; int n = 2; int dev_fd; /5。调用I/O函数(read/write)与客户端通讯。 int fd_led; fd_led = open(”/dev/led”,O_RDWR); if(fd_led 0) if(pfd0。revents = POLLIN) interface_print(te
16、mp); /*从终端读取数据/ memset(buf,0,sizeof(buf); ret = read(pfd0.fd,buf,sizeof(buf)1); if(ret /*发送数据给服务器/ write(sockfd,buf,ret); if(pfd1。revents = POLLIN) if(!strncmp(buf,get /*接收服务器发送的信息*/ memset(temp,0,sizeof(temp); ret = read(pfd1.fd,temp,sizeof(temp)1); if(ret tempret-1 = 0; /把信息显示到终端*/ interface_print(temp); else if(0 = ret) printf(超时n”); br