android震动系统开发全过程

上传人:mar****e6 文档编号:174177001 上传时间:2022-12-14 格式:DOCX 页数:6 大小:132.39KB
收藏 版权申诉 举报 下载
android震动系统开发全过程_第1页
第1页 / 共6页
android震动系统开发全过程_第2页
第2页 / 共6页
android震动系统开发全过程_第3页
第3页 / 共6页
资源描述:

《android震动系统开发全过程》由会员分享,可在线阅读,更多相关《android震动系统开发全过程(6页珍藏版)》请在装配图网上搜索。

1、Android震动系统开发全过程5一、前言本人刚学习安卓驱动开发,水平不能说菜,是根本没有水平,在这里把学习过程贴出来,跟大家一起学习交流,还望大家多多指正,转载的请标明出处。二、android驱动介绍安卓总体架构是在Linux内核基础上,增加硬件抽象层(HAL),运行库,java虚拟机,程序框架等组成的,具体如下图。HardwareAbstractionLayerqpcnGL|E5IlfAl-_-7HanicrCartLibniriflt賦郦林IAPPLICATICNS毗Zr1Gimli忖卢ClockAPPLIEATIDNRRAMEWORKActMty-ManagerManasrLinuxK

2、ernei_Drivr?ButfactliDriverU5R口抽刖WiA口听比九udi臼焙MlPp羽fCalendarPacoAlbumAin尺口F匚)RLINTIN1Ej.;LIBRARIES銘旷觀;厂履赢安卓的应用程序是从applicationframework层架构上建立的。所有APK应用程序都是通过framework层来运行的。applicationframework是google写好的,除非自己深度定制,一般是不会更改这个层的。对于驱动开发来讲,我们要做的就是让framework层能认识并操作我们的硬件设备就0K了。因此我们关心主要有3个层面:linuxKernel层HAL层1. J

3、NI层linuxKernel:是google在linux内核基础上,专门为移动设备优化后的内核,增加修改一些东西,担修改的不多,对于内核驱动来讲,基本没有修改,做过linux驱动开发的人应该很容易理解。2. HAL,硬件抽象层:简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(UserSpace),一层放在内核空间(KernelSpace),其中,硬件抽象层运行在用户空间。用户空间不属于内核不必遵守GPL协议,各个厂商可以把与自己硬件设备相关,具有商业机密的一些代码放在HAL层。3. JNI层:提供java和底

4、层C、C+的动态链接库的接口。我理解的是JNI就是一个代理,可以把C和C+生成的接口函数翻译成Java可用,提供给framework层。三、振动系统开发过程1.硬件平台CPU:IMX6Q4核1GRAM:1GFLASH:8G板载这次开发用的代码都是google和飞思卡尔提供的具体的就不再说明了,因为每个平台代码都有所不同,而且买开发板时候都会带相应的资料。2. 震动系统是android里面比较简单的一个系统,我采用的是从高层到底层的学习方式。因为我们的驱动最终是给应用程序用的,从application的需求分析JNI,然后分析HAL最后在我们写linuxkernel驱动时候,很容易理解为什么要这

5、么写。好了开始正式分析。3. Application层:通过google我找到关于APK访问震动的如下说明:A、通过系统服务获得手机震动服务,Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);B、得到震动服务后检测vibrator是否存在:vibrator.hasVibrator();检测当前硬件是否有vibrator,如果有返回true,如果没有返回false。C、根据实际需要进行适当的调用,vibrator.vibrate(longmilliseconds);开始启动vibrator持续milliseconds毫秒。

6、vibrator.vibrate(longpattern,intrepeat);以pattern方式重复repeat次启动vibrator。(pattern的形式为newIongarg1,arg2,arg3,arg4.,其中以两个一组的如arg1和arg2为一组、arg3和arg4为一组,每一组的前一个代表等待多少毫秒启动vibrator,后一个代表vibrator持续多少毫秒停止,之后往复即可。Repeat表示重复次数,当其为-1时,表示不重复只以pattern的方式运行一次)。D、vibrator.cancel();Vibrator停止。从上面的说明,可以看出应用程序调用震动系统,是调用一

7、个叫VIBRATOR_SERVICE的服务,这个服务有3个函数,分别是hasVibrator(),r.vibrate,.cancel();当然这个三个函数可能在framework层进行的另一层的封装,我没有去深究。但可以推测出JNI层要做的是与注册VIBRATOR_SERVICE服务和实现这三个函数相关的.HAL层:这一层我找到了具体的代码我们会好分析很多,其代码是:androidframeworksbaseservicesjnicom_android_server_VibratorService.cpp#defineLOG_TAGVibratorService#includejni.h#in

8、cludeJNIHelp.h#includeandroid_runtime/AndroidRuntime.h#include#include#include#includenamespaceandroidstaticjbooleanvibratorExists(JNIEnv*env,jobjectclazz)/判断振动器是否存在returnvibrator_exists()0?JNI_TRUE:JNI_FALSE;staticvoidvibratorOn(JNIEnv*env,jobjectclazz,jlongtimeout_ms)/打开振动器/LOGI(vibratorOnn);vibra

9、tor_on(timeout_ms);staticvoidvibratorOff(JNIEnv*env,jobjectclazz)/关闭振动器/LOGI(vibratorOffn);vibrator_off();staticJNINativeMethodmethod_table=vibratorExists,()Z,(void*)vibratorExists,vibratorOn,(J)V,(void*)vibratorOn,vibratorOff,()V,(void*)vibratorOff;intregister_android_server_VibratorService(JNIEnv*

10、env)注册vibrator服.务returnjniRegisterNativeMethods(env,com/android/server/VibratorService,method_table,NELEM(method_table);从上面代码可以看出,JNI做了两件事:其一注册vibrator服务,其二,实现了vibratorExists,vibratorOn,vibratorOff三个服务函数。进而我们可以分析出HAL层主要的就是实现次代码里调用的三个函数vibrator_exists(),vibrator_on(timeout_ms),vibrator_off()。HAL层:经过各

11、种查找我们找到了vibrator的hal层代码:android40hardwarelibhardware_legacyvibratorvibrator.c#include#includeqemu.h#include#include#include#include#defineTHE_DEVICE/sys/class/timed_output/vibrator/enableintvibrator_exists()/判断振动器是否存在intfd;#ifdefQEMU_HARDWARE/模拟器情况下实现此功能if(qemu_check()return1;#endiffd=open(THE_DEVIC

12、E,O_RDWR);if(fd0)return0;close(fd);return1;staticintsendit(inttimeout_ms)打开振动器timeout_ms毫秒intnwr,ret,fd;charvalue20;#ifdefQEMU_HARDWARE/模拟器情况下实现次功能if(qemu_check()returnqemu_control_command(vibrator:%d,timeout_ms);#endiffd=open(THE_DEVICE,O_RDWR);if(fd0)returnerrno;nwr=sprintf(value,%dn,timeout_ms);r

13、et=write(fd,value,nwr);close(fd);return(ret=nwr)?0:-1;intvibrator_on(inttimeout_ms)/*constanton,uptomaximumallowedtime*/returnsendit(timeout_ms);intvibrator_off()/关闭振动器就是设置振动器打开时间为0returnsendit(0);分析上面代码可以看出,HAL访问这个设备是打开/sys/class/timed_output/vibrator/enable,这个设备文件,然后向文件中写入打开时间来完成设备操作的。因此很容易我们可以推断出

14、,linuxkernel层是要生成这个设备文件然后,实现相应的函数。4. Linuxkernel层:通过上面分析我们大概了解了内核驱动所要实现的功能。通过各种参考资料,我查到了这个设备驱动是通过timed_output框架来实现的,有框架在又简单了不少,我们找到timed_output框架实现的函数在:kerneldriversstagingandroidtimed_output.c#include#include#include#include#include#includetimed_output.hstaticstructclass*timed_output_class;staticat

15、omic_tdevice_count;staticssize_tenable_show(structdevice*dev,structdevice_attribute*attr,char*buf)structtimed_output_dev*tdev=dev_get_drvdata(dev);intremaining=tdev-get_time(tdev);returnsprintf(buf,%dn,remaining);staticssize_tenable_store(structdevice*dev,structdevice_attribute*attr,constchar*buf,si

16、ze_tsize)structtimed_output_dev*tdev=dev_get_drvdata(dev);intvalue;if(sscanf(buf,%d,&value)!=1)return-EINVAL;tdev-enable(tdev,value);returnsize;staticDEVICE_ATTR(enable,S_IRUGO|S_IWUSR,enable_show,enable_store);staticintcreate_timed_output_class(void)if(!timed_output_class)timed_output_class=class_c

17、reate(THIS_MODULE,timed_output);if(IS_ERR(timed_output_class)returnPTR_ERR(timed_output_class);atomic_set(&device_count,0);return0;inttimed_output_dev_register(structtimed_output_dev*tdev)intret;if(!tdev|!tdev-name|!tdev-enable|!tdev-get_time)return-EINVAL;ret=create_timed_output_class();if(retindex

18、=atomic_inc_return(&device_count);tdev-dev=device_create(timed_output_class,NULL,MKDEV(0,tdev-index),NULL,tdev-name);if(IS_ERR(tdev-dev)returnPTR_ERR(tdev-dev);ret=device_create_file(tdev-dev,&dev_attr_enable);if(retdev,tdev);tdev-state=0;return0;err_create_file:device_destroy(timed_output_class,MKD

19、EV(0,tdev-index);printk(KERN_ERRtimed_output:Failedtoregisterdriver%sn,tdev-name);returnret;EXPORT_SYMBOL_GPL(timed_output_dev_register);voidtimed_output_dev_unregister(structtimed_output_dev*tdev)device_remove_file(tdev-dev,&dev_attr_enable);device_destroy(timed_output_class,MKDEV(0,tdev-index);dev

20、_set_drvdata(tdev-dev,NULL);EXPORT_SYMBOL_GPL(timed_output_dev_unregister);staticint_inittimed_output_init(void)returncreate_timed_output_class();staticvoid_exittimed_output_exit(void)class_destroy(timed_output_class);module_init(timed_output_init);module_exit(timed_output_exit);MODULE_AUTHOR(MikeLo

21、ckwood);MODULE_DESCRIPTION(timedoutputclassdriver);MODULE_LICENSE(GPL);kerneldriversstagingandroidtimed_output.h#ifndef_LINUX_TIMED_OUTPUT_H#define_LINUX_TIMED_OUTPUT_Hstructtimed_output_devconstchar*name;/*enabletheoutputandsetthetimer*/void(*enable)(structtimed_output_dev*sdev,inttimeout);/*return

22、sthecurrentnumberofmillisecondsremainingonthetimer*/int(*get_time)(structtimed_output_dev*sdev);/*privatedata*/structdevice*dev;intindex;intstate;externinttimed_output_dev_register(structtimed_output_dev*dev);externvoidtimed_output_dev_unregister(structtimed_output_dev*dev);#endif分析上面代码可以看出,我们的驱动是要实

23、现timed_output_dev结构体,然后注册这个结构体就行了。下面我们开始真正动手。由于本人水平有限,参考了samung个公开kernel的代码里的马达驱动。写出了自己的驱动:本人硬件的马达通过P4.17脚控制高打开低关闭kernel_imxdriversvibratorvibrator.c#include#include#include#include#include#include#include#include#include#include#include#defineIMX_GPIO_NR(bank,nr)(bank)-1)*32+(nr)/IO定义#defineSABRESD

24、_VIBRATOR_CTLIMX_GPIO_NR(4,17)/电机通过P4.17脚控制高打开低关闭#defineMAX_TIMEOUT10000/*10s*/最长可打开10sstaticstructvibratorstructwake_lockwklock;/wake_lock防止震动过程中系统休眠,线程不释放此设备,造成不必要错误structhrtimertimer;/高精度定时器structmutexlock;/互斥锁,防止多线程同时访问这个设备.structwork_structwork;/设备操作队列,用于一次操作完成和下一次开始同步用(三星这么用的,具体为什么不直接用回调函数,我也不

25、懂,还望大神们私信给个说明感激不尽)vibdata;staticvoidmx6_vibrator_off(void)gpio_direction_output(SABRESD_VIBRATOR_CTL,0);wake_unlock(&vibdata.wklock);/震动关闭就可以释放wake_lock锁voidmx6_motor_enable(structtimed_output_dev*sdev,intvalue)mutex_lock(&vibdata.lock);/关键代码段,同一时间只允许一个线程执行/*cancelprevioustimerandsetGPIOaccordingtov

26、alue*/当先前定时器完成后关闭这个定时器/当上次震动完成后关闭这次动作/开始震动打开wakelock锁不允许休眠hrtimer_cancel(&vibdata.timer);cancel_work_sync(&vibdata.work);if(value)wake_lock(&vibdata.wklock);gpio_direction_output(SABRESD_VIBRATOR_CTL,1);if(value0)if(valueMAX_TIMEOUT)value=MAX_TIMEOUT;value+=45;/为了使震动变得明显,固定增加一个时间.跟硬件有关系hrtimer_start

27、(&vibdata.timer,/开始定时器ns_to_ktime(u64)value*NSEC_PER_MSEC),HRTIMER_MODE_REL);elsemx6_vibrator_off();mutex_unlock(&vibdata.lock);/关键代码段执行完成,释放互斥锁intmx6_get_time(structtimed_output_dev*sdev)if(hrtimer_active(&vibdata.timer)/读取剩余时间按并返回ktime_tr=hrtimer_get_remaining(&vibdata.timer);returnktime_to_ms(r);

28、return0;structtimed_output_devmx6_motot_driver=/注意这个名字,由于HAL层里面的设备为/sys/class/timed_output/vibrator/enable/因此这个名字必须为vibrator.name=vibrator,.enable=mx6_motor_enable,.get_time=mx6_get_time,;staticenumhrtimer_restartmx6_vibrator_timer_func(structhrtimer*timer)/定时器结束时候的回调函数schedule_work(&vibdata.work);定

29、时器完成了执行work队列回调函数来关闭电机returnHRTIMER_NORESTART;staticvoidmx6_vibrator_work(structwork_struct*work)/工作队列处理函数,当工作队列执行当/schedule_work时候执行mx6_vibrator_off();void_initmx6_motor_init()intret=0;hrtimer_init(&vibdata.timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);/初始化定时器vibdata.timer.function=mx6_vibrator_timer_fun

30、c;/设置回调函数INIT_WORK(&vibdata.work,mx6_vibrator_work);/初始化工作队列ret=gpio_request(SABRESD_VIBRATOR_CTL,vibrator-en);/申请IOif(ret0)printk(vibratorrequestIOerr!:%dn,ret);returnret;wake_lock_init(&vibdata.wklock,WAKE_LOCK_SUSPEND,vibrator);/初始化wake_lockmutex_init(&vibdata.lock);/初始化互斥锁ret=timed_output_dev_re

31、gister(&mx6_motot_driver);/注册timed_output设备if(ret0)gotoerr_to_dev_reg;return0;err_to_dev_reg:/错误了就释放所有资源mutex_destroy(&vibdata.lock);wake_lock_destroy(&vibdata.wklock);gpio_free(SABRESD_VIBRATOR_CTL);printk(vibratorerr!:%dn,ret);returnret;voidmx6_motor_exit()mutex_destroy(&vibdata.lock);wake_lock_de

32、stroy(&vibdata.wklock);gpio_free(SABRESD_VIBRATOR_CTL);printk(vibratorexit!n);timed_output_dev_register(&mx6_motot_driver);module_init(mx6_motor_init);module_exit(mx6_motor_exit);MODULE_AUTHOR();MODULE_DESCRIPTION(MotorVibratordriver);MODULE_LICENSE(GPL);自此完成了驱动的所有内容,编译,烧写!有两种方法可以测试是否成功:其一就是系统启动后,打开

33、一个带振动的APP看能否实现震动功能。其二调试口中向设备文件中写数据.列如:echo1000/sys/class/timed_output/vibrator/enable/震动1S中试验成功!大功告成!这里总结一下:通过这个例程学会了安卓驱动开发的一般步骤,对安卓每个层的认识都有深入。是个非常好的开始。这种从上往下的分析方法只适合于简单的系统,和项目时间要求不高的情况下,我在分析上就浪费了不少时间。项目比较紧张的话,直接百度一个历程按照说明改一下就成了,复杂的系统涉及的东西太多,比如视频之类的,一路分析下去的话可能半个月不一定能搞定。这个驱动属于非常简单,但是实际动手时候,还是多参考别人的例程,毕竟水平不高,再简单的驱动也不一定能想的周全。

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!