Linux驱动开发_数码相册项目、360WIFI驱动移植介绍

【摘要】 这篇文章介绍两个知识点: 数码相册要求介绍、贴出案例代码、介绍360随身wifi的驱动移植注意事项。
任务1: 文件系统本地挂载 任务2:数码相册项目代码 ​ 数码相册功能:
1.​ 支持两种格式图片显示: bmp、jpg
区分两种图片格式,通过后缀名称区分。
2.​ 支持触摸屏、按键方式翻页(支持前后翻页)
建立双向链表,调用读取目录的函数(opendir),将目录下所有符合要求的图片加入到链表里。
3.​ 支持三轴加速度计,实现姿态感应。根据三轴加速度的姿态,调整图片的显示方向。
4.​ 支持图片的自适应: 居中显示,超大尺寸的图片需要自动缩小到屏幕能够显示的大小。
5.​ 居中显示。
6.​ 数码相册需要有状态栏: 当前系统的时间信息,当前图片的名称、数量。
倒车影像、usb摄像头网页视频控制、广告机。
案例代码:
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include touch_input.h#include key_input.h#include mma7660_input.h#include framebuffer.h#include image_zoom.h#include list.h#include imagedecoding.hstruct photoa_lbum_info photo_album_info; /*重要结构*//*函数功能: 处理捕获到的信号*/void exit_sighandler(int sig){ printf(捕获到信号_%d\n,sig); exit(0); /*结束进程*/}/*函数功能: 图片类型过滤函数返回值: 0表示支持,其他值表示不支持*/int imagetypefiltering(char *name){ /*1. 查找后缀*/ char *jpg_p=strstr(name,.jpg); char *jpeg_p=strstr(name,.jpeg); char *bmp_p=strstr(name,.bmp); char *jpg_p=strstr(name,.jpg); char *jpeg_p=strstr(name,.jpeg); char *bmp_p=strstr(name,.bmp); /*2. 过滤后缀*/ if(jpg_p==null&&jpeg_p==null&&bmp_p==null&& jpg_p==null&&jpeg_p==null&&bmp_p==null) { return -1; } /* 123.mp4.mp3 123.c.txt p=strstr(123.c.txt,.c); p执行 *p=. */ /*3. 名称比较,二次过滤*/ int jpg_p_cmp=1; int jpeg_p_cmp=1; int bmp_p_cmp=1; int jpg_p_cmp=1; int jpeg_p_cmp=1; int bmp_p_cmp=1; if(jpg_p)jpg_p_cmp=strcmp(jpg_p,.jpg); if(jpeg_p)jpeg_p_cmp=strcmp(jpeg_p,.jpeg); if(bmp_p)bmp_p_cmp=strcmp(bmp_p,.bmp); if(jpg_p)jpg_p_cmp=strcmp(jpg_p,.jpg); if(jpeg_p)jpeg_p_cmp=strcmp(jpeg_p,.jpeg); if(bmp_p)bmp_p_cmp=strcmp(bmp_p,.bmp); if(jpg_p_cmp!=0&&jpeg_p_cmp!=0&&bmp_p_cmp!=0&& jpg_p_cmp!=0&&jpeg_p_cmp!=0&&bmp_p_cmp!=0) { return -2; } return 0;}/*函数功能: 遍历指定的目录,将图片的绝对路径加入到链表函数参数: 传入目录名称函数返回值: 负数表示失败, 大于0表示加入到链表里节点的数量*/int traverse_directory(char *dir_name){ int cnt=0; /*1. 先清空链表*/ remove_all_node(); /*2. 打开目录*/ dir *dir=opendir(dir_name); if(dir==null) { dbug_printf(%s 目录打开失败!\n,dir_name); return -1; } /*3. 循环遍历目录*/ struct dirent *dir_info=null; struct image_liststruct *temp=null; int len; while(dir_info=readdir(dir)) { /*过滤图片*/ if(imagetypefiltering(dir_info->d_name)!=0) { dbug_printf(不符合要求的文件: %s\n,dir_info->d_name); continue; } cnt++; //给新节点申请空间 temp=malloc(sizeof(struct image_liststruct)); //计算文件名称长度(绝对路径): len=strlen(dir_name)+strlen(dir_info->d_name)+1; //给存放文件名称指针申请空间 temp->file_name=malloc(len); strcpy(temp->file_name,dir_name); strcat(temp->file_name,dir_info->d_name); /*4. 添加链表节点*/ addlistnode(listhead,temp); } return cnt;}/*函数功能: 删除链表里所有的节点*/int remove_all_node(void){ struct image_liststruct *p=listhead; //保存头地址 struct image_liststruct *tmp=null; if(p==null) /*头为空就创建一个头*/ { p=listhead=createlisthead(listhead); } if(p->next==null)return 0;/*节点为空不需要删除*/ else { tmp=p; //保存上一个节点的地址---也就是头的地址,因为链表头不需要删除 p=p->next; /*移动到下一个数据节点*/ tmp->next=null; /*指定头的下一个节点为null*/ } while(p!=null) { tmp=p; //保存上一个节点的地址 p=p->next; /*偏移到下一个节点*/ /*删除节点*/ free(tmp->file_name); free(tmp); } return 0;}/*函数功能: 在屏幕左下角实时显示当前时间*/void *time_pthread_func(void *dev){ time_t sec_time; time_t sec_tmp; struct tm *system_time; char timebuff[20]; while(1) { /*获取本地秒单位时间*/ sec_time=time(null); if(sec_tmp!=sec_time) { sec_tmp=sec_time; /*使用时间函数将秒单位时间转为标准时间返回*/ system_time=localtime(&sec_time); /*格式化打印时间*/ strftime(timebuff,20,%y-%m-%d %h:%m:%s,system_time); /*清除底状态栏*/ framebuffer_fill(0,photo_album_info.framebuffer_var.yres-gbk_font_size,19*gbk_font_size/2,photo_album_info.framebuffer_var.yres,0xd1eeee); /*在指定位置进行显示时间*/ framebuffer_string(0,photo_album_info.framebuffer_var.yres-gbk_font_size,timebuff); } }}/*函数功能: gui界面初始化代码*/void gui_init(void){ /*1. 清屏初始化*/ framebuffer_fill(0,0,photo_album_info.framebuffer_var.xres,photo_album_info.framebuffer_var.yres,0x33ffcc); /*清除整个屏幕*/ framebuffer_fill(0,0,photo_album_info.framebuffer_var.xres,gbk_font_size,0xd1eeee); /*清除顶状态栏*/ framebuffer_fill(0,photo_album_info.framebuffer_var.yres-gbk_font_size,photo_album_info.framebuffer_var.xres,photo_album_info.framebuffer_var.yres,0xd1eeee); /*清除底状态栏*/ /*2. 项目名称显示(居中显示)*/ framebuffer_string((photo_album_info.framebuffer_var.xres-strlen(project_name)*(gbk_font_size/2))/2, 0,project_name);}int main(int argc,char **argv){ int current_cnt=1; /*保存当前图片的位置*/ struct image_liststruct *list_current_p=null; /*用于保存节点的位置*/ struct imagedecodinginfo image_info={0,0,null}; /*保存当前图片解码信息*/ int current_x=0; /*显示图片时,x坐标起始位置*/ int current_y=0; /*显示图片时,y坐标起始位置*/ char currentnumberstr[50]; /*显示当前数量字符串*/ photo_album_info.lcd_direction=1; /*屏幕默认方向*/ if(argc!=2) { printf(传入的参数格式: ./app \n); return 0; } /*1. 注册将要捕获的信号*/ signal(sigint,exit_sighandler); /*ctrl+c发出*/ signal(sigsegv,exit_sighandler); /*进程产生非法内存访问时发出*/ /*2. 初始化帧缓冲设备*/ if(framebuffer_device_init(&photo_album_info)!=0)exit(1); /*3. 字库初始化*/ if(fontlib_init()!=0)exit(1); /*4. 创建读取触摸屏坐标的线程*/ pthread_t touch_thread_id; pthread_create(&touch_thread_id,null,touch_pthread_func,null); pthread_detach(touch_thread_id); /*5. 创建读取按键值的线程*/ pthread_t key_thread_id; pthread_create(&key_thread_id,null,key_pthread_func,null); pthread_detach(key_thread_id); /*6. 创建读取三轴加速度计姿态的线程*/ pthread_t mma7660_thread_id; pthread_create(&mma7660_thread_id,null,mma7660_pthread_func,null); pthread_detach(mma7660_thread_id); /*7. 创建显示时间的线程*/ pthread_t time_thread_id; pthread_create(&time_thread_id,null,time_pthread_func,null); pthread_detach(time_thread_id); /*8. 创建链表头*/ listhead=createlisthead(listhead); if(listhead==null) { printf(创建链表头失败!\n); exit(1); } while(1) { list_current_p=listhead; /*保存头地址*/ current_cnt=1; /*位置置1*/ /*遍历指定目录,保存图片名称到链表,并返回图片的总数量*/ photo_album_info.image_number=traverse_directory(argv[1]); /*打印链表里的节点信息*/ pintlistinfo(listhead); /*偏移到数据节点*/ list_current_p=list_current_p->next; while(list_current_p) { /*1. 等待加速计输入事件*/ /*2. 判断图片类型,开始显示图片*/ if(strstr(list_current_p->file_name,.jpg)||strstr(list_current_p->file_name,.jpeg)|| strstr(list_current_p->file_name,.jpg)||strstr(list_current_p->file_name,.jpeg)) { /*2.1 解码jpeg图片*/ if(decoding_jpegimage(list_current_p->file_name,&image_info)) { printf(%s图片解码失败!\n,list_current_p->file_name); } } else if(strstr(list_current_p->file_name,.bmp)||strstr(list_current_p->file_name,.bmp)) { /*2.2 解码bmp图片,得到图片信息*/ if(decoding_bmpimage(list_current_p->file_name,&image_info)) { printf(%s图片解码失败!\n,list_current_p->file_name); } } /*3. 判断是否解码成功*/ if(image_info.rgb==null || image_info.height==0 || image_info.width==0) { goto free_mem; /*解码失败,继续下一张*/ } /*4. 解码成功,在lcd屏上显示*/ /*判断lcd屏剩余尺寸是否足够显示图片,不够显示就缩小*/ if(image_info.height>photo_album_info.framebuffer_var.yres-gbk_font_size*2|| image_info.width>photo_album_info.framebuffer_var.xres) { int maximum_height; int zoom_proportion; int maximum_width; if(image_info.height>=image_info.width) /*如果图片高度大于宽度,那么缩放就以高度为准*/ { maximum_height=photo_album_info.framebuffer_var.yres-gbk_font_size*2;/*屏幕最大能够显示的高度*/ zoom_proportion=image_info.height-maximum_height; /*缩放比例*/ maximum_width=image_info.width-zoom_proportion; /*宽度根据高度进行比例缩放*/ dbug_printf(height:缩放之后的实际尺寸(宽*高):%d*%d\n,maximum_width,maximum_height); /*再次判断缩放之后图片宽度在lcd屏是否足够显示,如果不够,则进行缩小*/ if(maximum_width>photo_album_info.framebuffer_var.xres) { } } else/*如果图片宽度大于高度,那么缩放就以宽度为准*/ { maximum_width=photo_album_info.framebuffer_var.xres; /*屏幕最大能够显示的宽度*/ zoom_proportion=image_info.width-maximum_width; /*缩放比例*/ maximum_height=image_info.height-zoom_proportion; /*高度根据宽度进行比例缩放*/ /*再次判断缩放之后图片高度在lcd屏是否足够显示,如果不够,则进行缩小*/ if(maximum_height>photo_album_info.framebuffer_var.yres-gbk_font_size*2) { /*高度以屏幕最大高度为准*/ maximum_height=photo_album_info.framebuffer_var.yres-gbk_font_size*2; /*高度缩小了,那么宽度也要按照比例缩小,否则会导致图片变形*/ maximum_width=maximum_height-(maximum_height-photo_album_info.framebuffer_var.yres-gbk_font_size*2); } dbug_printf(width:缩放之后的实际尺寸(宽*高):%d*%d\n,maximum_width,maximum_height); } /*申请空间存放缩放之后的数据*/ unsigned char *rgb_zoom=malloc(maximum_width*maximum_height*3); if(rgb_zoom==null) { perror(存放图片缩放数据的空间申请失败!); goto free_mem; } /*将图片按照指定的尺寸进行缩小*/ if(image_zoom(image_info.rgb,image_info.width,image_info.height,rgb_zoom,maximum_width,maximum_height)!=0) { goto free_mem; } /*缩放成功,保存缩放之后图片实际参数*/ image_info.height=maximum_height; image_info.width=maximum_width; free(image_info.rgb); /*释放源rgb空间*/ image_info.rgb=rgb_zoom; /*指针指向缩放之后的rgb数据空间*/ /*显示图片的坐标起始位置*/ current_x=(photo_album_info.framebuffer_var.xres-maximum_width)/2;; current_y=(photo_album_info.framebuffer_var.yres-maximum_height)/2; } else /*尺寸足够显示,进行居中显示*/ { /*计算显示图片时,xy坐标位置--保证居中显示*/ current_x=(photo_album_info.framebuffer_var.xres-image_info.width)/2; current_y=(photo_album_info.framebuffer_var.yres-image_info.height)/2; } /*清空显示区域*/ framebuffer_fill(0,gbk_font_size,photo_album_info.framebuffer_var.xres,photo_album_info.framebuffer_var.yres-gbk_font_size,0x33ffcc); /*在lcd指定位置显示图片*/ dbug_printf(在lcd显示的位置:x=%d,y=%d\n,current_x,current_y); framebuffer_displayimages(current_x, /*横坐标位置*/ current_y, /*纵坐标位置*/ image_info.width, image_info.height, image_info.rgb); dbug_printf(显示: 第%d个节点的数据=%s\n,current_cnt,list_current_p->file_name); /*图片显示的数量情况*/ sprintf(currentnumberstr,%d/%d,photo_album_info.image_number,current_cnt); /*清除底状态栏*/ framebuffer_fill((photo_album_info.framebuffer_var.xres-(strlen(currentnumberstr)*gbk_font_size/2))/2-32, photo_album_info.framebuffer_var.yres-gbk_font_size, photo_album_info.framebuffer_var.xres, photo_album_info.framebuffer_var.yres,0xd1eeee); /*在指定位置显示当前数量*/ framebuffer_string((photo_album_info.framebuffer_var.xres-(strlen(currentnumberstr)*gbk_font_size/2))/2, photo_album_info.framebuffer_var.yres-gbk_font_size,currentnumberstr); /*在右下角显示当前图片名称*/ framebuffer_string(photo_album_info.framebuffer_var.xres/2+(strlen(currentnumberstr)*gbk_font_size/2)/2 +gbk_font_size*2, photo_album_info.framebuffer_var.yres-gbk_font_size,basename(list_current_p->file_name));free_mem: if(image_info.rgb) /*判断空间是否申请成功*/ { free(image_info.rgb); /*释放空间*/ image_info.rgb=null; } image_info.height=0; image_info.width=0; /*等待按键信号和触摸屏信号进行翻页 或者有切换屏幕的操作时进行切换屏幕方向*/ while(!photo_album_info.page_direction&&!photo_album_info.lcd_state){} if(photo_album_info.page_direction==1) /*右翻页*/ { list_current_p=list_current_p->next; current_cnt++; /*记录图片位置*/ } else if(photo_album_info.page_direction==2)/*左翻页*/ { if(current_cnt>1) { list_current_p=list_current_p->old; current_cnt--; /*记录图片位置*/ } } photo_album_info.page_direction=0; /*状态清0*/ photo_album_info.lcd_state=0; /*状态清0*/ } } return 0;} 任务3: 360 wifi驱动测试、无线工具使用 \12 20181210 文件系统本地挂载、360wifi驱动与相关无线工具安装\参考资料\01 360usb无线网卡驱动及相关无线工具安装\03 wifi驱动及相关工具库一键移植文件\360wifi_20170926.tar
​ udhcpc自动分配ip地址的命令,需要的脚本和使用方法
​ 两个脚本里的代码。
​ wifi的配置文件
​ 一键移植文件布局。
[root@wbyq 360wifi]# ls
360wifi_1.sh 360wifi_2.sh bin etc lib mt7601usta.ko simple.script
[root@wbyq 360wifi]# tree
.
├── 360wifi_1.sh
├── 360wifi_2.sh
├── bin
│   ├── ifrename
│   ├── iwconfig
│   ├── iwevent
│   ├── iwgetid
│   ├── iwlist
│   ├── iwpriv
│   ├── iwspy
│   ├── wpa_cli
│   ├── wpa_supplicant
│   └── wpa_supplicant.conf
├── etc
│   ├── wireless
│   │   └── rt2870sta
│   │   ├── rt2870sta.dat
│   │   └── rt2870sta.dat~
│   └── wpa_supplicant.conf
├── lib
│   └── libiw.so.29
├── mt7601usta.ko
└── simple.script
5 directories, 18 files
[root@wbyq 360wifi]#
​ usb设备匹配的流程
当前usb设备插到电脑的usb口上之后,usb产生usb中断,usb主机就会发生特定命令,询问插入
进来的设备,是什么设备。设备会按照usb协议的规定,回应一个数据包---结构体。
主机收到数据包之后会进行解析,会按照设备的类型或者设备id进行在内核里寻找与之匹配的驱动,
寻找成功就会调用usb驱动程序。
​ 启动脚本连接wifi
[root@tiny4412 etc]#vi wpa_supplicant.conf //修改将要连接的路由器名称和密码
[root@tiny4412 etc]#cd /work/360wifi/
[root@tiny4412 360wifi]#ls
360wifi_1.sh bin lib simple.script
360wifi_2.sh etc mt7601usta.ko
[root@tiny4412 360wifi]#./360wifi_2.sh //运行脚本2,安装wifi驱动,启动wifi连接热点,连接上之后再分配ip地址
[ 917.120000] rtusb init rt2870 --->
[ 917.120000] <-- rtmpalloctxrxringmemory, status=0
[ 917.120000] <-- rtmpallocadapterblock, status=0
[ 917.120000] bulk in maxpacketsize = 512
[ 917.120000] ep address = 0x84
[ 917.120000] bulk in maxpacketsize = 512
[ 917.120000] ep address = 0x85
[ 917.120000] bulk out maxpacketsize = 512
[ 917.125000] ep address = 0x 8
[ 917.130000] bulk out maxpacketsize = 512
[ 917.130000] ep address = 0x 4
[ 917.135000] bulk out maxpacketsize = 512
[ 917.140000] ep address = 0x 5
[ 917.145000] bulk out maxpacketsize = 512
[ 917.145000] ep address = 0x 6
[ 917.150000] bulk out maxpacketsize = 512
[ 917.155000] ep address = 0x 7
[ 917.155000] bulk out maxpacketsize = 512
[ 917.160000] ep address = 0x 9
[ 917.170000] usbcore: registered new interface driver rt2870
[ 917.350000] current mac: =b0:d5:9d:0c:51:29
[ 917.355000] nicreadeepromparameters: rxpath = 1, txpath = 1
[ 917.360000] 20mhz bw, 2.4g band-03030505, adata = 03030505, gdata = 03030505
[ 917.365000] 20mhz bw, 2.4g band-00000004, adata = 00000004, gdata = 00000004
[ 917.365000] 20mhz bw, 2.4g band-00000002, adata = 00000002, gdata = 00000002
[ 917.365000] 20mhz bw, 2.4g band-00000002, adata = 00000002, gdata = 00000002
[ 917.370000] 20mhz bw, 2.4g band-ffff0002, adata = ffff0002, gdata = ffff0002
[ 917.610000] buildchannel # 1 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 2 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 3 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 4 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 5 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 6 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 7 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 8 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 9 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 10 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 11 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 12 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 13 :: pwr0 = 6, pwr1 =0, flags = 0
buildchannel # 14 :: pwr0 = 6, pwr1 =0, flags = 0
rxwiwirelesscliid == bssid_wcidfailed
[ 920.090000] key = 28:fd:b8:58:c5:ce:85:e5:33:97:d8:09:8d:46:c2:6a
[ 920.090000] rx mic key = 00:00:00:00:00:00:00:00
[ 920.090000] tx mic key = 00:00:00:00:00:00:00:00 (表示wifi已经成功连接热点)
sending discover...
[ 923.340000] cmdthread : cmdthread_set_asic_wcid : wcid = 1, settid = 10000, deletetid = ffffffff.
[ 923.340000] 1-macvalue= e02d6594,
[ 923.340000] 2-macvalue= 1701d,
sending select for 192.168.43.240...
lease of 192.168.43.240 obtained, lease time 3600
setting ip address 192.168.43.240 on ra0
deleting routers
route: siocdelrt: no such process
adding router 192.168.43.1
recreating /etc/resolv.conf
adding dns server 192.168.43.1 //表示wifi已经成功分配了ip地址
​ 查看网卡ip地址,ping百度测试是否可以访问外网
​ 查看当前wifi连接的网卡信息
​ 通过wifi管理工具,扫描周边的热点
[root@tiny4412 360wifi]#iwlist scanning

自主研发的光斑检测产品!能帮企业,科研机构以及高校提高研发效率的利器
不仅仅只是销量高,口碑还非常好的手机,确实很耐用!
EMC测试内容及故障排除、解决的基本方法
手机支持频段有哪些?
Linux要如何学习
Linux驱动开发_数码相册项目、360WIFI驱动移植介绍
日本电产新宝推出用于无人搬运台车及自主移动机器人的驱动模块新产品
简析Zynq芯片中PS和PL之间的9个双向读写的通信端口
引脚炉后变色现象
华为最新科技比5G还猛
中国计量大学等在智能光电材料与传感技术领域取得重要进展
诺基亚在印起诉OPPO
电动显微镜载物台在光学显微镜升级中的应用
Molex推出坚固耐用的Brad HarshIO M8以太网模块
比亚迪与Grenergy达成全球最大储能合作,投资额14亿美元
派克汉尼汾推出新型VSO®最大功率微型比例阀,小功耗支持大流量
iPhone X再出险情,面容ID被怀疑或侵犯个人隐私
上海新阳半导体启动位于合肥新站高新技术产业开发区的第二生产基地项目建设
mos管短路保护电路的原理和应用
VR竞技体育 Racket Nx引爆电子竞技革命