首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android 驱动跟系统开发 2. 解析模拟器GPS模块 (原创)

2012-09-27 
Android 驱动和系统开发 2. 解析模拟器GPS模块 (原创)好久没有写技术博客了,恰逢今天还感冒了,这破天气,晚

Android 驱动和系统开发 2. 解析模拟器GPS模块 (原创)

好久没有写技术博客了,恰逢今天还感冒了,这破天气,晚上凉风一吹,就感冒了,要加强锻炼呀。

好了,废话不多说,由于工作需要,我要移植一个虚拟的gps模块,于是乎,我就参考了android模拟器的gps模块的实现方法,只需稍微改动就完成了我的工作了,随后我也会附上我做的模块的代码,这里主要还是来解析下模拟器上的gps模块代码吧。

相信做过android location方面应用的同志都知道,android 模拟器虽然没有真正的GPS功能,但是DDMS可以模拟GPS,通过telnet连接到adb,然后发送GPS数据,再转化成NMEA格式的信号给android系统,就可以模拟出location功能了,相信用过的童鞋都知道,没用过的同志去搜索一下就知道了,这里我就不多说了,我主要还是来分析一下这个模拟的功能是如何实现的,这里还是膜拜一下写android源码的大神们,多看看源码,学到的东西很多呢。

首先,我们直入主题,对于移植系统的人来说(比如说我),关注的是中间部分的代码,android的framework层我们需要改动的很少,最多就是加点log来调试,驱动层呢,因为模拟器没有真实的设备,也不可能利用PC上的资源区模拟,因为PC是没有GPS模块的(除非你的电脑很高级),但是我想还是可以通过网络来得到地理位置的,虽然不是非常的准确,希望google的工程师可以去完善,呵呵,题外话了。说了这么多,我就是想说,android 模拟器中gps模块的功能主要依赖于2个东西,一个是ddms中的geo fix命令,还有一个是hal层中的gps_qemu.c中作为硬件抽象层的处理,把虚拟的数据上报给framework层。

主要层次如下图

Android 驱动跟系统开发 2. 解析模拟器GPS模块 (原创)

好了,思路清晰了,咱就看代码,位于源码目录下/sdk/emulator/gps/gps_qemu.c

首先我们要搞清楚,在andrroid中HAL 的一个位置问题,HAL是为了更好的封装好硬件驱动存在的,主要是一些接口,编译成库文件,给framework中国的jni来调用,我们这里的GPS模块会被编译成gps.goldfish.so文件,在同目录下的Android.mk中有写到


这图有点丑,不过大体思路还是清楚的,可以对照着代码看,这里使用的是event poll技术进行事件的处理,在线程中,把fd和control[1]加入了epoll中,设置为POLLIIN模式,当有事件发生是,就会调用相应的代码,这里的control[1],在这里做控制作用,只要是控制gps的开始和停止的,所以在线程外面对control[0]进行写操作的话,对应的control[1]就会收到相应的指令,然后采取措施。具体代码如下

static intdo_geo_fix( ControlClient  client, char*  args ){    // GEO_SAT2 provides bug backwards compatibility.    enum { GEO_LONG = 0, GEO_LAT, GEO_ALT, GEO_SAT, GEO_SAT2, NUM_GEO_PARAMS };    char*   p = args;    int     top_param = -1;    double  params[ NUM_GEO_PARAMS ];    int     n_satellites = 1;    static  int     last_time = 0;    static  double  last_altitude = 0.;    if (!p)        p = "";    /* tokenize */    while (*p) {        char*   end;        double  val = strtod( p, &end );        if (end == p) {            control_write( client, "KO: argument '%s' is not a number\n", p );            return -1;        }        params[++top_param] = val;        if (top_param + 1 == NUM_GEO_PARAMS)            break;        p = end;        while (*p && (p[0] == ' ' || p[0] == '\t'))            p += 1;    }    /* sanity check */    if (top_param < GEO_LAT) {        control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" );        return -1;    }    /* check number of satellites, must be integer between 1 and 12 */    if (top_param >= GEO_SAT) {        int sat_index = (top_param >= GEO_SAT2) ? GEO_SAT2 : GEO_SAT;        n_satellites = (int) params[sat_index];        if (n_satellites != params[sat_index]            || n_satellites < 1 || n_satellites > 12) {            control_write( client, "KO: invalid number of satellites. Must be an integer between 1 and 12\r\n");            return -1;        }    }    /* generate an NMEA sentence for this fix */    {        STRALLOC_DEFINE(s);        double   val;        int      deg, min;        char     hemi;        /* format overview:         *    time of fix      123519     12:35:19 UTC         *    latitude         4807.038   48 degrees, 07.038 minutes         *    north/south      N or S         *    longitude        01131.000  11 degrees, 31. minutes         *    east/west        E or W         *    fix quality      1          standard GPS fix         *    satellites       1 to 12    number of satellites being tracked         *    HDOP             <dontcare> horizontal dilution         *    altitude         546.       altitude above sea-level         *    altitude units   M          to indicate meters         *    diff             <dontcare> height of sea-level above ellipsoid         *    diff units       M          to indicate meters (should be <dontcare>)         *    dgps age         <dontcare> time in seconds since last DGPS fix         *    dgps sid         <dontcare> DGPS station id         */        /* first, the time */        stralloc_add_format( s, "$GPGGA,%06d", last_time );        last_time ++;        /* then the latitude */        hemi = 'N';        val  = params[GEO_LAT];        if (val < 0) {            hemi = 'S';            val  = -val;        }        deg = (int) val;        val = 60*(val - deg);        min = (int) val;        val = 10000*(val - min);        stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)val, hemi );        /* the longitude */        hemi = 'E';        val  = params[GEO_LONG];        if (val < 0) {            hemi = 'W';            val  = -val;        }        deg = (int) val;        val = 60*(val - deg);        min = (int) val;        val = 10000*(val - min);        stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)val, hemi );        /* bogus fix quality, satellite count and dilution */        stralloc_add_format( s, ",1,%02d,", n_satellites );        /* optional altitude + bogus diff */        if (top_param >= GEO_ALT) {            stralloc_add_format( s, ",%.1g,M,0.,M", params[GEO_ALT] );            last_altitude = params[GEO_ALT];        } else {            stralloc_add_str( s, ",,,," );        }        /* bogus rest and checksum */        stralloc_add_str( s, ",,,*47" );        /* send it, then free */        android_gps_send_nmea( stralloc_cstr(s) );        stralloc_reset( s );    }    return 0;}

通过穿进去的经纬度,海拔等信息转化成NMEA格式的gps数据,然后通过socket发出去。


这部分就介绍到这里,之后会更精彩,哈哈。

希望这篇文章对读者有帮助,完全是参考android源码的,对我来说源码是最好的学习途径。


1楼zhangjie201412昨天 10:45
自己先顶一个,希望对大家有帮助

热点排行