android震动vibrator系统开发全过程.docx

上传人:b****8 文档编号:30349351 上传时间:2023-08-13 格式:DOCX 页数:17 大小:133.05KB
下载 相关 举报
android震动vibrator系统开发全过程.docx_第1页
第1页 / 共17页
android震动vibrator系统开发全过程.docx_第2页
第2页 / 共17页
android震动vibrator系统开发全过程.docx_第3页
第3页 / 共17页
android震动vibrator系统开发全过程.docx_第4页
第4页 / 共17页
android震动vibrator系统开发全过程.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

android震动vibrator系统开发全过程.docx

《android震动vibrator系统开发全过程.docx》由会员分享,可在线阅读,更多相关《android震动vibrator系统开发全过程.docx(17页珍藏版)》请在冰豆网上搜索。

android震动vibrator系统开发全过程.docx

android震动vibrator系统开发全过程

Android震动系统开发全过程

一、前言

本人刚学习安卓驱动开发,水平不能说菜,是根本没有水平,在这里把学习过程贴出来,跟大家一起学习交流,还望大家多多指正,转载的请标明出处。

二、android驱动介绍

安卓总体架构是在Linux内核基础上,增加硬件抽象层(HAL),运行库,java虚拟机,程序框架等组成的,具体如下图。

安卓的应用程序是从applicationframework层架构上建立的。

所有APK应用程序都是通过framework层来运行的。

applicationframework是google写好的,除非自己深度定制,一般是不会更改这个层的。

对于驱动开发来讲,我们要做的就是让framework层能认识并操作我们的硬件设备就OK了。

因此我们关心主要有3个层面:

linuxKernel层

HAL层

JNI层

1.linuxKernel:

是google在linux内核基础上,专门为移动设备优化后的内核,增加修改一些东西,担修改的不多,对于内核驱动来讲,基本没有修改,做过linux驱动开发的人应该很容易理解。

2.HAL,硬件抽象层:

简单来说,就是对Linux 内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。

也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间。

用户空间不属于内核不必遵守GPL协议,各个厂商可以把与自己硬件设备相关,具有商业机密的一些代码放在HAL层。

3.JNI层:

提供java和底层C、C++的动态链接库的接口。

我理解的是JNI就是一个代理,可以把C和C++生成的接口函数翻译成Java可用,提供给framework层。

三、振动系统开发过程

1.硬件平台

CPU:

IMX6Q4核1G

RAM:

1G

FLASH:

8G板载

这次开发用的代码都是google和飞思卡尔提供的具体的就不再说明了,因为每个平台代码都有所不同,而且买开发板时候都会带相应的资料。

2.震动系统是android里面比较简单的一个系统,我采用的是从高层到底层的学习方式。

因为我们的驱动最终是给应用程序用的,从application的需求分析JNI,然后分析HAL最后在我们写linuxkernel驱动时候,很容易理解为什么要这么写。

好了开始正式分析。

3.Application层:

通过google我找到关于APK访问震动的如下说明:

A、通过系统服务获得手机震动服务,Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);

B、得到震动服务后检测vibrator是否存在:

vibrator.hasVibrator();

检测当前硬件是否有vibrator,如果有返回true,如果没有返回false。

C、根据实际需要进行适当的调用,

vibrator.vibrate(longmilliseconds);

开始启动vibrator持续milliseconds毫秒。

vibrator.vibrate(long[]pattern,intrepeat);

以pattern方式重复repeat次启动vibrator。

(pattern的形式为newlong[]{arg1,arg2,arg3,arg4......},其中以两个一组的如arg1和arg2为一组、arg3和arg4为一组,每一组的前一个代表等待多少毫秒启动vibrator,后一个代表vibrator持续多少毫秒停止,之后往复即可。

Repeat表示重复次数,当其为-1时,表示不重复只以pattern的方式运行一次)。

D、vibrator.cancel();

Vibrator停止。

从上面的说明,可以看出应用程序调用震动系统,是调用一个叫VIBRATOR_SERVICE的服务,这个服务有3个函数,分别是hasVibrator(),r.vibrate,.cancel();当然这个三个函数可能在framework层进行的另一层的封装,我没有去深究。

但可以推测出JNI层要做的是与注册VIBRATOR_SERVICE服务和实现这三个函数相关的.

4.HAL层:

这一层我找到了具体的代码我们会好分析很多,其代码是:

android\frameworks\base\services\jni\com_android_server_VibratorService.cpp

#defineLOG_TAG"VibratorService"

#include"jni.h"

#include"JNIHelp.h"

#include"android_runtime/AndroidRuntime.h"

#include

#include

#include

#include

namespaceandroid

{

staticjbooleanvibratorExists(JNIEnv*env,jobjectclazz)//判断振动器是否存在

{

returnvibrator_exists()>0?

JNI_TRUE:

JNI_FALSE;

}

staticvoidvibratorOn(JNIEnv*env,jobjectclazz,jlongtimeout_ms)//打开振动器

{

//LOGI("vibratorOn\n");

vibrator_on(timeout_ms);

}

staticvoidvibratorOff(JNIEnv*env,jobjectclazz)//关闭振动器

{

//LOGI("vibratorOff\n");

vibrator_off();

}

staticJNINativeMethodmethod_table[]={

{"vibratorExists","()Z",(void*)vibratorExists},

{"vibratorOn","(J)V",(void*)vibratorOn},

{"vibratorOff","()V",(void*)vibratorOff}

};

intregister_android_server_VibratorService(JNIEnv*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()。

5.HAL层:

经过各种查找我们找到了vibrator的hal层代码:

\android40\hardware\libhardware_legacy\vibrator\vibrator.c

#include

#include"qemu.h"

#include

#include

#include

#include

#defineTHE_DEVICE"/sys/class/timed_output/vibrator/enable"

intvibrator_exists()//判断振动器是否存在

{

intfd;

#ifdefQEMU_HARDWARE//模拟器情况下实现此功能

if(qemu_check()){

return1;

}

#endif

fd=open(THE_DEVICE,O_RDWR);

if(fd<0)

return0;

close(fd);

return1;

}

staticintsendit(inttimeout_ms)//打开振动器timeout_ms毫秒

{

intnwr,ret,fd;

charvalue[20];

#ifdefQEMU_HARDWARE//模拟器情况下实现次功能

if(qemu_check()){

returnqemu_control_command("vibrator:

%d",timeout_ms);

}

#endif

fd=open(THE_DEVICE,O_RDWR);

if(fd<0)

returnerrno;

nwr=sprintf(value,"%d\n",timeout_ms);

ret=write(fd,value,nwr);

close(fd);

return(ret==nwr)?

0:

-1;

}

intvibrator_on(inttimeout_ms)

{

/*constanton,uptomaximumallowedtime*/

returnsendit(timeout_ms);

}

intvibrator_off()//关闭振动器就是设置振动器打开时间为0

{

returnsendit(0);

}

分析上面代码可以看出,HAL访问这个设备是打开/sys/class/timed_output/vibrator/enable,这个设备文件,然后向文件中写入打开时间来完成设备操作的。

因此很容易我们可以推断出,linuxkernel层是要生成这个设备文件然后,实现相应的函数。

6.Linuxkernel层:

通过上面分析我们大概了解了内核驱动所要实现的功能。

通过各种参考资料,我查到了这个设备驱动是通过timed_output框架来实现的,有框架在又简单了不少,我们找到timed_output框架实现的函数在:

\kernel\drivers\staging\android\timed_output.c

#include

#include

#include

#include

#include

#include"timed_output.h"

staticstructclass*timed_output_class;

staticatomic_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,"%d\n",remaining);

}

staticssize_tenable_store(

structdevice*dev,structdevice_attribute*attr,

constchar*buf,size_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_create(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(ret<0)

returnret;

tdev->index=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(ret<0)

gotoerr_create_file;

dev_set_drvdata(tdev->dev,tdev);

tdev->state=0;

return0;

err_create_file:

device_destroy(timed_output_class,MKDEV(0,tdev->index));

printk(KERN_ERR"timed_output:

Failedtoregisterdriver%s\n",

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_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("MikeLockwood");

MODULE_DESCRIPTION("timedoutputclassdriver");

MODULE_LICENSE("GPL");

\kernel\drivers\staging\android\timed_output.h

#ifndef_LINUX_TIMED_OUTPUT_H

#define_LINUX_TIMED_OUTPUT_H

structtimed_output_dev{

constchar*name;

/*enabletheoutputandsetthetimer*/

void(*enable)(structtimed_output_dev*sdev,inttimeout);

/*returnsthecurrentnumberofmillisecondsremainingonthetimer*/

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

分析上面代码可以看出,我们的驱动是要实现timed_output_dev结构体,然后注册这个结构体就行了。

下面我们开始真正动手。

由于本人水平有限,参考了samung一个公开kernel的代码里的马达驱动。

写出了自己的驱动:

本人硬件的马达通过P4.17脚控制高打开低关闭

\kernel_imx\drivers\vibrator\vibrator.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include<../drivers/staging/android/timed_output.h>

#defineIMX_GPIO_NR(bank,nr)(((bank)-1)*32+(nr))//IO定义

#defineSABRESD_VIBRATOR_CTLIMX_GPIO_NR(4,17)//电机通过P4.17脚控制高打开低关闭

#defineMAX_TIMEOUT10000/*10s*///最长可打开10s

staticstructvibrator{

structwake_lockwklock;//wake_lock防止震动过程中系统休眠,线程不释放此设备,造成不必要错误

structhrtimertimer;//高精度定时器

structmutexlock;//互斥锁,防止多线程同时访问这个设备.

structwork_structwork;//设备操作队列,用于一次操作完成和下一次开始同步用(三星这么用的,具体为什么不直接用回调函数,我也不懂,还望大神们私信给个说明感激不尽)

}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);//关键代码段,同一时间只允许一个线程执行

/*cancelprevioustimerandsetGPIOaccordingtovalue*/

hrtimer_cancel(&vibdata.timer);//当先前定时器完成后关闭这个定时器

cancel_work_sync(&vibdata.work);//当上次震动完成后关闭这次动作

if(value)

{

wake_lock(&vibdata.wklock);//开始震动打开wakelock锁不允许休眠

gpio_direction_output(SABRESD_VIBRATOR_CTL,1);

if(value>0)

{

if(value>MAX_TIMEOUT)

value=MAX_TIMEOUT;

value+=45;//为了使震动变得明显,固定增加一个时间.跟硬件有关系

hrtimer_start(&vibdata.timer,//开始定时器

ns_to_ktime((u64)value*NSEC_PER_MSEC),

HRTIMER_MODE_REL);

}

}

else

mx6_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);

}

return0;

}

structtimed_output_devmx6_motot_driver={

.name="vibrator",//注意这个名字,由于HAL层里面的设备为//"/sys/class/timed_output/vibrator/enable"

//因此这个名字必须为"vibrator"

.enable=mx6_motor_enable,

.get_time=mx6_get_time,

};

staticenumhrtimer_restartmx6_vibrator_timer_

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 唐诗宋词

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1