当前位置:   article > 正文

android gps tty,Gps HAL层分析

hw_module_methods_t gps_module_methods

1.Android 6.0源码中Gps HAL层代码分析

我们知道gps在HAL层是库的方式存在的,它的库的名称是gps.default.so,我们可以根据这个命令来查找find –name Android.mk –exec grep –l “gps.default” {} \;,我们获取的文件的路径在如下位置:fspad-733-6.0/androidM/device/softwinner/common/hardware/libhardware/libgps

我们可以打开Android.mk查看这个动态库依赖的源码

从这个源码中我们不难发现这个动态库依赖的源码为gps_ql.c ql-log.c config.c这三个文件。我们先从gps_ql.c这个文件分析。Gps HAL定义的结构体是hw_module_t,按照以往的分析方法,这里我们重点关心methods。

struct hw_module_t HAL_MODULE_INFO_SYM = {

.tag = HARDWARE_MODULE_TAG,

.version_major = 1,

.version_minor = 0,

.id = GPS_HARDWARE_MODULE_ID,

.name = "QUECTEL GPS Module",

.author = "Joe.Wang",

.methods = &gps_module_methods,

};

static struct hw_module_methods_t gps_module_methods = {

.open = open_gps

};

static int open_gps(const struct hw_module_t* module, char const* name,

struct hw_device_t** device)

{

struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));

memset(dev, 0, sizeof(*dev));

dev->common.tag = HARDWARE_DEVICE_TAG;

dev->common.version = 0;

dev->common.module = (struct hw_module_t*)module;

dev->get_gps_interface = gps__get_gps_interface;

*device = (struct hw_device_t*)dev;

return 0;

}

在这个open函数中就是对gps_device_t的这个结构体初始化,在这个结构体中重要的就是get_gps_interface这个函数指针的初始化。dev->get_gps_interface = gps__get_gps_interface;所以接下来我们就要分析gps__get_gps_interface;函数。

struct gps_device_t {

struct hw_device_t common;

const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);

};

const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)

{

return &qlGpsInterface;

}

当jni代码代用这个函数的时候,它会向jni代码返回一个GpsInterface结构体,jni代码所在Android6.0的源码位置如下:frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp,GpsInterface这个结构体的成员如下:

typedef struct {

size_t          size;     //此结构体所占内存大小

int   (*init)( GpsCallbacks* callbacks ); //初始化,获取回调接口

int   (*start)( void );  //开始采集数据

int   (*stop)( void );   //停止采集数据

void  (*cleanup)( void ); //释放回调接口

int   (*inject_time)(GpsUtcTime time, int64_t timeReference,int uncertainty);

//校准当前时间

int  (*inject_location)(double latitude, double longitude, float accuracy);

//校准当前位置(经纬度)

......

} GpsInterface;

这个结构体被填充的成员如下,其实就是qlGpsInterface返回给上层的值。

static const GpsInterface  qlGpsInterface = {

sizeof(GpsInterface),

ql_gps_init,

ql_gps_start,

ql_gps_stop,

ql_gps_cleanup,

ql_gps_inject_time,

ql_gps_inject_location,

ql_gps_delete_aiding_data,

ql_gps_set_position_mode,

ql_gps_get_extension,

};

这个函数被填充好之后是共上层来回调的,那个jni代码是如何调用hal层?,jni代码的文件位置在前面我们已经说过了,接下来它的代码实现过程如下:

static JNINativeMethod sMethods[] = {

/* name, signature, funcPtr */

{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},

{"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},

{"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},

{"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},

{"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},

{"native_inject_location","(DDF)V",(void*)android_location_GpsLocationProvider_inject_location},

......

}

android_location_GpsLocationProvider_class_init_native函数完成的工作如下:

①Hw_get_module通过ID = GPS_HARDWARE_MODULE_ID来查找硬件抽象层的模块

②module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);回调硬件抽象层的open方法。

③sGpsInterface = gps_device->get_gps_interface(gps_device);调用hal层get_gps_interface中的方法,返回前面我们看到的填充好的结构体。

android_location_GpsLocationProvider_init函数完成的功能:

①回调上述初始化好的结构体中的init方法。

if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)

②向hal传递初始化好的sGpsCallbacks,这里面的函数是有hal层来回调的。

GpsCallbacks sGpsCallbacks = {

sizeof(GpsCallbacks),

location_callback,

status_callback,

sv_status_callback,

nmea_callback,

set_capabilities_callback,

acquire_wakelock_callback,

release_wakelock_callback,

create_thread_callback,

request_utc_time_callback,

};

其他的函数功能我们等下再分析,我们按照代码的执行流程来查看这个过程,我们接下来看硬件抽象层的init函数。

在init函数中首先会检查模块的类型,检查的过程如下

ret = check_module_type();

get_config();

read_config(GPS_CONFIG_FILE_PATH); // #define GPS_CONFIG_FILE_PATH "gps_cfg.inf"

#从这里我们能够清楚的看到它会读取当前目录下的gps_cfg.inf的配置文件。

读取过程如下:

①定义二维数组,并对数组初始化为*

static char value[CFG_NUM][CFG_CONTENT_LENGTH];  // CFG_NUM 13

//CFG_CONTENT_LENGTH 50

memset(value,'*',CFG_NUM * CFG_CONTENT_LENGTH);

②打开gps_cfg.inf文件

file = fopen(config_file_path,"r");

③读取内容,每次读取127个字节

while(fgets(buf, sizeof(buf) - 1,file) != NULL)

如果开头有”#”,”;”,’\0’,’\r’,’\n’等这些字符,那么就跳过该行的读取,接着读取下一行。

接着通过strstr(buf,QL_head[i]),pt = strchr(ph,' '); strcpy(value[i], ph);这三个函数终将读取的数据写到value这个二维数组中,按什么读取那?就是上面我们看到的QL_head[i]这个数组。数组的成员如下:

接着调用get_config函数将前面读取到的数据复制到字符串中,有MODULE_TYPE,GPS_CHANNEL,BAUD_RATE等内容。

在check_module_type(void)函数中会对数据头信息,驱动的设备节点检查,检测完成之后调用波特率初始化函数。但是我们发现这些检测并没有做直接通过return返回了。

检查完参数之后我们重新回到init函数中,将jni中传递过来的callbacks函数赋值给callback_p的这个变量中,接着定义GpsState的结构体,这是保存gps状态的,

当这些赋值完成之后,调用gps_state_init函数进行初始化,初始化的过程如下:

从上面的代码我们能够清楚的看到,它的功能如下:

①初始化GpsState结构体

②打开/dev/ttyUSB1

③串口波特率的初始化(8位,波特率115200等)

④使用Socketpair创建进程间通讯的全双工的管道

⑤回调jni代码中创建线程的函数(为什么不在这里面直接创建线程那?因为这样创建的线程和java虚拟机没有关联,pthread_create创建的线程在内存中,所以这里需要回调来创建)。

我们可以看下线程体所做的工作,对应的函数是gps_state_thread。

我们发现这里的epoll监听了两个文件描述符,其中一个就是前面创建的管道描述符,其次是监听的poll(上报数据)的描述符。

在管道fd监听到事件之后通过如下步骤执行

ret = read( fd, &cmd, 1 );   //读取管道中的内容,其实就是如下的命令码

cmd == CMD_QUIT

cmd == CMD_START

cmd == CMD_STOP

但是在这个代码中此处的read并没有使用,在Android5.0在start函数中发信号,然后这个里接收信号,开始读取数据。而6.0是通过epoll函数来监听打开的/dev/ttyUSB1的方式来读取数据的。读取数据的过程如下:

nevents = epoll_wait( epoll_fd, events, 2, -1 );

if ((events[ne].events & EPOLLIN) != 0)

else if (fd == gps_fd)

ret = read( fd, buff, sizeof(buff) );       //读取数据

nmea_reader_addc( reader, buff[nn] );  //数据处理

nmea_reader_parse( r );          //数据解析

终我们可以看到将数据更新,这里更新完数据之后会调用回调函数,将数据传递给jni代码,jni代码通过如下函数将数据更新到应用层APP,至此整个代码就分析完成了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/236449
推荐阅读
相关标签
  

闽ICP备14008679号